Example usage for java.math BigDecimal subtract

List of usage examples for java.math BigDecimal subtract

Introduction

In this page you can find the example usage for java.math BigDecimal subtract.

Prototype

public BigDecimal subtract(BigDecimal subtrahend) 

Source Link

Document

Returns a BigDecimal whose value is (this - subtrahend) , and whose scale is max(this.scale(), subtrahend.scale()) .

Usage

From source file:org.openbravo.test.costing.TestCosting.java

@Test
public void testCostingN5() throws Exception {

    final int day0 = 0;
    final int day1 = 5;
    final int day2 = 10;
    final int day3 = 15;
    final int day4 = 20;
    final BigDecimal price1 = new BigDecimal("5.00");
    final BigDecimal price2 = new BigDecimal("7.00");
    final BigDecimal price3 = new BigDecimal("6.6667");
    final BigDecimal price4 = new BigDecimal("5.40");
    final BigDecimal quantity1 = new BigDecimal("10");
    final BigDecimal quantity2 = new BigDecimal("8");
    final BigDecimal quantity3 = new BigDecimal("12");

    try {//w w  w  . j  a v  a  2 s .  c  o m

        OBContext.setOBContext(USER_ID, ROLE_ID, CLIENT_ID, ORGANIZATION_ID);
        OBContext.setAdminMode(true);

        // Create a new product for the test
        Product product = createProduct(price1);

        // Create goods receipt, run costing background, post it and assert it
        ShipmentInOut goodsReceipt1 = createGoodsReceipt(product, price1, quantity1, day0);

        // Create goods shipment, run costing background, post it and assert it
        ShipmentInOut goodsShipment1 = createGoodsShipment(product, price1, quantity2, day2);

        // Create purchase order and book it
        Order purchaseOrder = createPurchaseOrder(product, price2, quantity1, day3);

        // Create goods receipt, run costing background, post it and assert it
        ShipmentInOut goodsReceipt2 = createGoodsReceipt(purchaseOrder, price2, quantity1, day4);

        // Create goods shipment, run costing background, post it and assert it
        ShipmentInOut goodsShipment2 = createGoodsShipment(product, price3, quantity1, day1);

        // Run price correction background
        runPriceBackground();

        // Assert product transactions
        List<ProductTransactionAssert> productTransactionAssertList = new ArrayList<ProductTransactionAssert>();
        productTransactionAssertList.add(
                new ProductTransactionAssert(OBDal.getInstance().get(ShipmentInOut.class, goodsReceipt1.getId())
                        .getMaterialMgmtShipmentInOutLineList().get(0), price1, price1));
        productTransactionAssertList.add(new ProductTransactionAssert(OBDal.getInstance()
                .get(ShipmentInOut.class, goodsShipment2.getId()).getMaterialMgmtShipmentInOutLineList().get(0),
                price3, price1));
        productTransactionAssertList.add(new ProductTransactionAssert(OBDal.getInstance()
                .get(ShipmentInOut.class, goodsShipment1.getId()).getMaterialMgmtShipmentInOutLineList().get(0),
                price1, price1));
        productTransactionAssertList.add(
                new ProductTransactionAssert(OBDal.getInstance().get(ShipmentInOut.class, goodsReceipt2.getId())
                        .getMaterialMgmtShipmentInOutLineList().get(0), price2, price4, price2));
        assertProductTransaction(product.getId(), productTransactionAssertList);

        // Assert product costing
        List<MaterialTransaction> transactionList = getProductTransactions(product.getId());
        List<ProductCostingAssert> productCostingAssertList = new ArrayList<ProductCostingAssert>();
        productCostingAssertList
                .add(new ProductCostingAssert(transactionList.get(0), price1, null, price1, quantity1));
        productCostingAssertList.add(new ProductCostingAssert(transactionList.get(3), price2, price3, price2,
                quantity3.subtract(quantity1)));
        assertProductCosting(product.getId(), productCostingAssertList);

        // Assert cost adjustment
        List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
        List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
        List<CostAdjustmentAssert> costAdjustmentAssertLineList = new ArrayList<CostAdjustmentAssert>();
        costAdjustmentAssertLineList.add(new CostAdjustmentAssert(transactionList.get(1), "BDT",
                quantity1.multiply(price1).add(quantity1.multiply(price3).negate()), day1, true));
        costAdjustmentAssertLineList.add(new CostAdjustmentAssert(transactionList.get(3), "NSC",
                quantity1.multiply(price4).add(quantity1.multiply(price2).negate()), day4, false, false));
        costAdjustmentAssertList.add(costAdjustmentAssertLineList);
        assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);

        // Post cost adjustment and assert it
        postDocument(costAdjustmentList.get(0));
        List<DocumentPostAssert> documentPostAssertList1 = new ArrayList<DocumentPostAssert>();
        documentPostAssertList1.add(new DocumentPostAssert("99900", amount0,
                quantity1.multiply(price3).add(quantity1.multiply(price1).negate()), null));
        documentPostAssertList1.add(new DocumentPostAssert("35000",
                quantity1.multiply(price3).add(quantity1.multiply(price1).negate()), amount0, null));
        documentPostAssertList1.add(new DocumentPostAssert("61000",
                quantity1.multiply(price2).add(quantity1.multiply(price4).negate()), amount0, null));
        documentPostAssertList1.add(new DocumentPostAssert("35000", amount0,
                quantity1.multiply(price2).add(quantity1.multiply(price4).negate()), null));
        CostAdjustment costAdjustment = OBDal.getInstance().get(CostAdjustment.class,
                costAdjustmentList.get(0).getId());
        assertDocumentPost(costAdjustment, product.getId(), documentPostAssertList1);

        OBDal.getInstance().commitAndClose();

    } catch (Exception e) {
        System.out.println(e.getMessage());
        throw new OBException(e);
    }

    finally {
        OBContext.restorePreviousMode();
    }
}

From source file:com.osafe.events.CheckOutEvents.java

public static String setShipGroups(HttpServletRequest request, HttpServletResponse response) {
    LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
    Delegator delegator = (Delegator) request.getAttribute("delegator");
    Locale locale = UtilHttp.getLocale(request);
    ShoppingCart shoppingCart = ShoppingCartEvents.getCartObject(request);
    String sItemTotalQty = request.getParameter("itemTotalQuantity");
    String sNumberOfItems = request.getParameter("numberOfItems");
    int iNumberOfItems = Integer.valueOf(sNumberOfItems);
    int iItemTotalQty = 0;
    BigDecimal bcartItemTotalQty = shoppingCart.getTotalQuantity();
    Map shippingContactMechMap = FastMap.newInstance();
    Map cartLineShippingContactMechQtyMap = FastMap.newInstance();
    Map cartLineShippingContactMechGiftMsgMap = FastMap.newInstance();
    Map cartLineQtyMap = FastMap.newInstance();
    Map cartLineProductInfoMap = FastMap.newInstance();
    Map cartItemQtyMap = FastMap.newInstance();
    List<MessageString> error_list = new ArrayList<MessageString>();
    MessageString messageString = null;/*from w  w w.j av  a 2s .c  om*/
    String message = null;
    if (UtilValidate.isNotEmpty(sItemTotalQty)) {
        iItemTotalQty = Integer.valueOf(sItemTotalQty).intValue();
    }

    /* Build quantity-product maps based on items on page */
    for (int i = 0; i < iItemTotalQty; i++) {
        String shippingContactMechId = request.getParameter("shippingContactMechId_" + i);
        String sCartLineIndex = request.getParameter("cartLineIndex_" + i);
        int iCartLineIndex = Integer.valueOf(sCartLineIndex).intValue();

        String qtyInCart = request.getParameter("qtyInCart_" + i);
        String productName = request.getParameter("productName_" + i);
        String productId = request.getParameter("productId_" + i);
        String productCategoryId = request.getParameter("productCategoryId_" + i);
        String prodCatalogId = request.getParameter("prodCatelogId_" + i);
        String unitPrice = request.getParameter("unitPrice_" + i);
        Map productInfoMap = FastMap.newInstance();
        productInfoMap.put("productName", productName);
        productInfoMap.put("productId", productId);
        productInfoMap.put("productCategoryId", productCategoryId);
        productInfoMap.put("prodCatalogId", prodCatalogId);
        productInfoMap.put("unitPrice", unitPrice);
        String giftMsgFrom = request.getParameter("lineItemGiftFrom_" + i);
        String giftMsgTo = request.getParameter("lineItemGiftTo_" + i);
        String giftMsg = request.getParameter("lineItemGiftMsg_" + i);
        Map giftMessageInfoMap = FastMap.newInstance();
        if (UtilValidate.isNotEmpty(giftMsgFrom)) {
            giftMessageInfoMap.put("from", giftMsgFrom);
        }
        if (UtilValidate.isNotEmpty(giftMsgTo)) {
            giftMessageInfoMap.put("to", giftMsgTo);
        }
        if (UtilValidate.isNotEmpty(giftMsg)) {
            giftMessageInfoMap.put("msg", giftMsg);
        }
        BigDecimal bLineQty = BigDecimal.ZERO;
        BigDecimal bShipQty = BigDecimal.ZERO;
        BigDecimal bCartQty = BigDecimal.ZERO;
        try {
            if (UtilValidate.isNotEmpty(qtyInCart)) {
                Double dQty = Double.valueOf(qtyInCart);
                if (UtilValidate.isInteger(qtyInCart) && dQty >= 0) {
                    bLineQty = BigDecimal.valueOf(dQty.doubleValue());
                } else {
                    bLineQty = BigDecimal.ZERO;
                    message = OSAFE_UI_LABELS.getString("PDPQtyDecimalNumberError");
                    message = StringUtil.replaceString(message, "_PRODUCT_NAME_", productName);
                    messageString = new MessageString(message, "qtyInCart_" + i, true);
                    error_list.add(messageString);

                }
            }
        } catch (Exception e) {
            bLineQty = BigDecimal.ZERO;
            message = OSAFE_UI_LABELS.getString("PDPQtyDecimalNumberError");
            message = StringUtil.replaceString(message, "_PRODUCT_NAME_", productName);
            messageString = new MessageString(message, "qtyInCart_" + i, true);
            error_list.add(messageString);

        }
        shippingContactMechMap.put(shippingContactMechId, shippingContactMechId);

        if (cartLineShippingContactMechQtyMap.containsKey(sCartLineIndex + "_" + shippingContactMechId)) {
            BigDecimal bTempQty = (BigDecimal) cartLineShippingContactMechQtyMap
                    .get(sCartLineIndex + "_" + shippingContactMechId);
            bShipQty = bShipQty.add(bTempQty);
        }
        bShipQty = bShipQty.add(bLineQty);
        cartLineShippingContactMechQtyMap.put(sCartLineIndex + "_" + shippingContactMechId, bShipQty);

        if (UtilValidate.isNotEmpty(giftMessageInfoMap)) {
            List lGiftMsg = null;
            if (cartLineShippingContactMechGiftMsgMap
                    .containsKey(sCartLineIndex + "_" + shippingContactMechId)) {
                lGiftMsg = (List) cartLineShippingContactMechGiftMsgMap
                        .get(sCartLineIndex + "_" + shippingContactMechId);
            } else {
                lGiftMsg = FastList.newInstance();
            }
            lGiftMsg.add(giftMessageInfoMap);
            cartLineShippingContactMechGiftMsgMap.put(sCartLineIndex + "_" + shippingContactMechId, lGiftMsg);
        }

        if (cartLineQtyMap.containsKey(sCartLineIndex)) {
            BigDecimal bTempQty = (BigDecimal) cartLineQtyMap.get(sCartLineIndex);
            bCartQty = bCartQty.add(bTempQty);
        }
        bCartQty = bCartQty.add(bLineQty);
        cartLineQtyMap.put(sCartLineIndex, bCartQty);
        cartLineProductInfoMap.put(sCartLineIndex, productInfoMap);
    }

    /* Validate Quantities entered */
    if (UtilValidate.isNotEmpty(cartLineQtyMap)) {
        try {

            String pdpQtyMin = Util.getProductStoreParm(request, "PDP_QTY_MIN");
            if (UtilValidate.isEmpty(pdpQtyMin)) {
                pdpQtyMin = "1";
            }
            String pdpQtyMax = Util.getProductStoreParm(request, "PDP_QTY_MAX");
            if (UtilValidate.isEmpty(pdpQtyMax)) {
                pdpQtyMax = "99";
            }
            BigDecimal bPdpQtyMin = BigDecimal.valueOf(Double.valueOf(pdpQtyMin).doubleValue());
            BigDecimal bPdpQtyMax = BigDecimal.valueOf(Double.valueOf(pdpQtyMax).doubleValue());

            Iterator<String> cartItemIter = cartLineQtyMap.keySet().iterator();
            while (cartItemIter.hasNext()) {
                String sCartLineIndex = cartItemIter.next();
                BigDecimal bChangeQty = (BigDecimal) cartLineQtyMap.get(sCartLineIndex);
                if (bChangeQty.compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                int iCartLineIndex = Integer.valueOf(sCartLineIndex).intValue();
                Map productInfoMap = (Map) cartLineProductInfoMap.get(sCartLineIndex);
                GenericValue prodPdpQtyMin = delegator.findOne("ProductAttribute",
                        UtilMisc.toMap("productId", productInfoMap.get("productId"), "attrName", "PDP_QTY_MIN"),
                        true);
                GenericValue prodPdpQtyMax = delegator.findOne("ProductAttribute",
                        UtilMisc.toMap("productId", productInfoMap.get("productId"), "attrName", "PDP_QTY_MAX"),
                        true);
                if (UtilValidate.isNotEmpty(prodPdpQtyMin) && UtilValidate.isNotEmpty(prodPdpQtyMax)) {
                    bPdpQtyMin = BigDecimal
                            .valueOf(Double.valueOf(prodPdpQtyMin.getString("attrValue")).doubleValue());
                    bPdpQtyMax = BigDecimal
                            .valueOf(Double.valueOf(prodPdpQtyMax.getString("attrValue")).doubleValue());
                }
                if (bChangeQty.compareTo(bPdpQtyMin) < 0) {
                    message = OSAFE_UI_LABELS.getString("PDPMinQtyError");
                    message = StringUtil.replaceString(message, "_PRODUCT_NAME_",
                            "" + productInfoMap.get("productName"));
                    message = StringUtil.replaceString(message, "_PDP_QTY_MIN_", "" + bPdpQtyMin.intValue());
                    messageString = new MessageString(message, "qtyInCart_" + sCartLineIndex, true);
                    error_list.add(messageString);

                }
                if (bChangeQty.compareTo(bPdpQtyMax) > 0) {
                    message = OSAFE_UI_LABELS.getString("PDPMaxQtyError");
                    message = StringUtil.replaceString(message, "_PRODUCT_NAME_",
                            "" + productInfoMap.get("productName"));
                    message = StringUtil.replaceString(message, "_PDP_QTY_MAX_", "" + bPdpQtyMax.intValue());
                    messageString = new MessageString(message, "qtyInCart_" + sCartLineIndex, true);
                    error_list.add(messageString);

                }

            }
        } catch (Exception e) {
            Debug.logError(e, "Error: updating cart quantity", module);
        }

    }
    if (error_list.size() != 0) {
        request.setAttribute("_ERROR_MESSAGE_LIST_", error_list);
        return "error";
    }
    /* Check the number of items passed from the screen matches the number of items in the cart.
     * If the number of items has changed remove all products from the cart and add back.
     * If the number of items have not changed remove zero quantities and set changed item quantities
     * The number of item check is essentially protecting against the usage of the back button.
     */
    if (UtilValidate.isNotEmpty(cartLineQtyMap)) {
        if (shoppingCart.items().size() != iNumberOfItems) {
            ShoppingCartItem shoppingCartItem = null;
            try {
                Iterator<ShoppingCartItem> cartItemIter = shoppingCart.items().iterator();
                while (cartItemIter.hasNext()) {
                    shoppingCartItem = (ShoppingCartItem) cartItemIter.next();
                    shoppingCart.removeCartItem(shoppingCartItem, dispatcher);
                }

                Iterator<String> cartLineItemIter = cartLineQtyMap.keySet().iterator();
                while (cartLineItemIter.hasNext()) {
                    String sCartLineIndex = cartLineItemIter.next();
                    BigDecimal bChangeQty = (BigDecimal) cartLineQtyMap.get(sCartLineIndex);
                    if (bChangeQty.compareTo(BigDecimal.ZERO) == 0) {
                        continue;
                    }
                    Map productInfoMap = (Map) cartLineProductInfoMap.get(sCartLineIndex);
                    String unitPrice = (String) productInfoMap.get("unitPrice");
                    BigDecimal bUnitPrice = null;
                    if (UtilValidate.isNotEmpty(unitPrice)) {
                        bUnitPrice = BigDecimal.valueOf(Double.valueOf(unitPrice).doubleValue());
                    }
                    if (UtilValidate.isEmpty(bUnitPrice)) {
                        message = OSAFE_UI_LABELS.getString("PDPMaxQtyError");
                        error_list.add(messageString);
                        request.setAttribute("_ERROR_MESSAGE_LIST_", error_list);
                        return "error";

                    }

                    ShoppingCartItem item = ShoppingCartItem.makeItem(null,
                            "" + productInfoMap.get("productId"), null, bChangeQty, bUnitPrice, null, null,
                            null, null, null, null, null, null, null, "" + productInfoMap.get("prodCatelogId"),
                            null, null, null, dispatcher, shoppingCart, Boolean.TRUE, Boolean.FALSE,
                            "" + productInfoMap.get("parentProductId"), Boolean.TRUE, Boolean.TRUE);
                    shoppingCart.addItemToEnd(item);
                    com.osafe.events.ShoppingCartEvents.setProductFeaturesOnCart(shoppingCart,
                            "" + productInfoMap.get("productId"));

                }

            } catch (Exception e) {
                Debug.logError("Error: removing cart item" + shoppingCartItem, module);
            }

        } else {
            try {

                Iterator<String> cartItemIter = cartLineQtyMap.keySet().iterator();
                while (cartItemIter.hasNext()) {
                    String sCartLineIndex = cartItemIter.next();
                    BigDecimal bChangeQty = (BigDecimal) cartLineQtyMap.get(sCartLineIndex);
                    int iCartLineIndex = Integer.valueOf(sCartLineIndex).intValue();
                    ShoppingCartItem shoppingCartItem = shoppingCart.findCartItem(iCartLineIndex);
                    if (bChangeQty.compareTo(BigDecimal.ZERO) == 0) {
                        shoppingCart.removeCartItem(shoppingCartItem, dispatcher);
                        continue;
                    }
                    if (bChangeQty.compareTo(shoppingCartItem.getQuantity()) != 0) {
                        shoppingCartItem.setQuantity(bChangeQty, dispatcher, shoppingCart);
                    }

                }
            } catch (Exception e) {
                Debug.logError("Error: updating cart quantity", module);
            }

        }

    }

    if (UtilValidate.isNotEmpty(shoppingCart.items())) {
        Iterator<ShoppingCartItem> cartItemIter = shoppingCart.items().iterator();
        int iItemIndex = 0;
        while (cartItemIter.hasNext()) {
            ShoppingCartItem shoppingCartItem = (ShoppingCartItem) cartItemIter.next();
            BigDecimal itemQuantity = shoppingCartItem.getQuantity();
            cartItemQtyMap.put("" + iItemIndex, itemQuantity);
            iItemIndex++;

            /* Clear Gift Messages per item.  Will be Reset
             * 
             */
            Map<String, String> orderItemAttributesMap = shoppingCartItem.getOrderItemAttributes();
            if (UtilValidate.isNotEmpty(orderItemAttributesMap)) {
                for (Entry<String, String> itemAttr : orderItemAttributesMap.entrySet()) {
                    String sAttrName = (String) itemAttr.getKey();
                    if (sAttrName.startsWith("GIFT_MSG_FROM_")) {
                        shoppingCartItem.removeOrderItemAttribute(sAttrName);

                    }
                    if (sAttrName.startsWith("GIFT_MSG_TO_")) {
                        shoppingCartItem.removeOrderItemAttribute(sAttrName);

                    }
                    if (sAttrName.startsWith("GIFT_MSG_TEXT_")) {
                        shoppingCartItem.removeOrderItemAttribute(sAttrName);

                    }

                }
            }
        }
    } else {
        return "emptyCart";

    }
    /* Clear item Ship Groups and create new ones */
    if (UtilValidate.isNotEmpty(shippingContactMechMap)) {
        Iterator<ShoppingCartItem> cartItemIter = shoppingCart.items().iterator();
        while (cartItemIter.hasNext()) {
            shoppingCart.clearItemShipInfo(cartItemIter.next());

        }
        shoppingCart.cleanUpShipGroups();

        Iterator<String> shipGroupIter = shippingContactMechMap.keySet().iterator();
        while (shipGroupIter.hasNext()) {
            int shipGroupIndex = shoppingCart.addShipInfo();
            String shippingContactMechId = shipGroupIter.next();
            shoppingCart.setShippingContactMechId(shipGroupIndex, shippingContactMechId);
            shippingContactMechMap.put(shippingContactMechId, Integer.valueOf(shipGroupIndex));

        }

    }

    if (UtilValidate.isNotEmpty(cartLineShippingContactMechQtyMap)) {
        Map<ShoppingCartItem, String> cartItemMessageCount = FastMap.newInstance();
        Iterator<String> cartLineShippingQtyIter = cartLineShippingContactMechQtyMap.keySet().iterator();
        while (cartLineShippingQtyIter.hasNext()) {
            String cartLineShippingContactMechKey = cartLineShippingQtyIter.next();
            int iKeySeparator = cartLineShippingContactMechKey.indexOf('_');

            String sCartLineIndex = cartLineShippingContactMechKey.substring(0, iKeySeparator);
            int iCartLineIndex = Integer.valueOf(sCartLineIndex);
            int iItemGiftMsgCount = 0;

            String shippingContactMechId = cartLineShippingContactMechKey.substring(iKeySeparator + 1);

            BigDecimal bShipQty = (BigDecimal) cartLineShippingContactMechQtyMap
                    .get(cartLineShippingContactMechKey);
            BigDecimal bCartItemQty = (BigDecimal) cartItemQtyMap.get(sCartLineIndex);
            BigDecimal bCartQty = BigDecimal.ZERO;
            if (UtilValidate.isNotEmpty(bCartItemQty)) {
                bCartQty = bCartItemQty;
            }
            BigDecimal bTotalShipGroupQty = BigDecimal.ZERO;
            BigDecimal bAddShipQty = BigDecimal.ZERO;

            if (bShipQty.compareTo(BigDecimal.ZERO) > 0) {
                Map shipGroupQtyMap = shoppingCart.getShipGroups(iCartLineIndex);
                Iterator shipGroupQtyIter = shipGroupQtyMap.keySet().iterator();
                while (shipGroupQtyIter.hasNext()) {
                    BigDecimal bShipGroupQty = (BigDecimal) shipGroupQtyMap.get(shipGroupQtyIter.next());
                    bTotalShipGroupQty = bTotalShipGroupQty.add(bShipGroupQty);
                }
                /* Total quantity designated to Ship has already been met */
                if (bTotalShipGroupQty.compareTo(bCartQty) == 0) {
                    continue;
                }
                /* If the ship quantity is greater than the quantity in the cart, set the ship quantity equal to cart quantity. */
                if (bShipQty.compareTo(bCartQty) > 0) {
                    bShipQty = bCartQty;
                }
                /* Add the Ship quantity to total ship quantity, If greater set the ship quantity to the quantity left that can be shipped
                 * (cart quantity minus total ship quantity) */
                bAddShipQty = bShipQty.add(bTotalShipGroupQty);
                if (bAddShipQty.compareTo(bCartQty) > 0) {
                    bShipQty = bCartQty.subtract(bTotalShipGroupQty);
                }
                if (bShipQty.compareTo(BigDecimal.ZERO) > 0) {
                    int shipGroupIndex = ((Integer) shippingContactMechMap.get(shippingContactMechId))
                            .intValue();
                    shoppingCart.setItemShipGroupQty(iCartLineIndex, bShipQty, shipGroupIndex);
                    /* Check Cart item Gift Messages going to this Ship Group (Address)
                     * 
                     */
                    List lGiftMsg = (List) cartLineShippingContactMechGiftMsgMap
                            .get(cartLineShippingContactMechKey);
                    if (UtilValidate.isNotEmpty(lGiftMsg)) {
                        ShoppingCartItem cartItem = shoppingCart.findCartItem(iCartLineIndex);
                        for (int i = 0; i < lGiftMsg.size(); i++) {
                            if (i > bShipQty.intValue()) {
                                break;
                            }
                            String sItemGiftMsgCount = (String) cartItemMessageCount.get(cartItem);
                            if (UtilValidate.isEmpty(sItemGiftMsgCount)) {
                                iItemGiftMsgCount = 1;
                            } else {
                                iItemGiftMsgCount = Integer.valueOf(sItemGiftMsgCount);
                                iItemGiftMsgCount++;

                            }

                            sItemGiftMsgCount = "" + iItemGiftMsgCount;
                            cartItemMessageCount.put(cartItem, sItemGiftMsgCount);

                            Map giftMsgMap = (Map) lGiftMsg.get(i);
                            String msgFrom = (String) giftMsgMap.get("from");
                            if (UtilValidate.isNotEmpty(msgFrom)) {
                                cartItem.setOrderItemAttribute(
                                        "GIFT_MSG_FROM_" + sItemGiftMsgCount + "_" + (shipGroupIndex + 1),
                                        msgFrom);

                            }
                            String msgTo = (String) giftMsgMap.get("to");
                            if (UtilValidate.isNotEmpty(msgTo)) {
                                cartItem.setOrderItemAttribute(
                                        "GIFT_MSG_TO_" + sItemGiftMsgCount + "_" + (shipGroupIndex + 1), msgTo);

                            }
                            String msg = (String) giftMsgMap.get("msg");
                            if (UtilValidate.isNotEmpty(msg)) {
                                cartItem.setOrderItemAttribute(
                                        "GIFT_MSG_TEXT_" + sItemGiftMsgCount + "_" + (shipGroupIndex + 1), msg);

                            }

                        }
                    }
                }

            }

        }

        /* Now check all quantities of each cart items have been assigned to a ship group
         * If not calculate and add the missing quantity to the last ship group defined for the item
         * */
        Iterator<ShoppingCartItem> cartItemIter = shoppingCart.items().iterator();
        while (cartItemIter.hasNext()) {
            ShoppingCartItem shoppingCartItem = (ShoppingCartItem) cartItemIter.next();

            BigDecimal bTotalShipGroupQty = BigDecimal.ZERO;
            BigDecimal bCartQty = shoppingCartItem.getQuantity();
            BigDecimal bShipGroupQty = BigDecimal.ZERO;
            int iShipGroupIndex = 0;

            Map shipGroupQtyMap = shoppingCart.getShipGroups(shoppingCartItem);
            Iterator shipGroupQtyIter = shipGroupQtyMap.keySet().iterator();
            while (shipGroupQtyIter.hasNext()) {
                iShipGroupIndex = Integer.valueOf(shipGroupQtyIter.next().toString());
                bShipGroupQty = (BigDecimal) shipGroupQtyMap.get(iShipGroupIndex);
                bTotalShipGroupQty = bTotalShipGroupQty.add(bShipGroupQty);

            }

            if (bTotalShipGroupQty.compareTo(bCartQty) < 0) {
                BigDecimal bAddShipQty = bCartQty.subtract(bTotalShipGroupQty);
                bAddShipQty = bAddShipQty.add(bShipGroupQty);

                shoppingCart.setItemShipGroupQty(shoppingCartItem, bAddShipQty, iShipGroupIndex);
            }
        }

        /* Clean up ship groups, if no quantities in group the group is removed.
         * If not calculate and add the missing quantity to the last ship group defined for the item
         * */
        shoppingCart.cleanUpShipGroups();

        /* Check ship group with multiple items, if more than one item in the group check
         * the shipping options available for each item,; if different count the group is split. 
         * */

        splitShipGroupByShipOptions(request, response);

    }

    return "success";
}

From source file:org.ofbiz.order.order.OrderServices.java

/** Service for checking and re-calc the tax amount */
public static Map<String, Object> recalcOrderTax(DispatchContext ctx, Map<String, ? extends Object> context) {
    LocalDispatcher dispatcher = ctx.getDispatcher();
    Delegator delegator = ctx.getDelegator();
    String orderId = (String) context.get("orderId");
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    Locale locale = (Locale) context.get("locale");

    // check and make sure we have permission to change the order
    Security security = ctx.getSecurity();
    boolean hasPermission = OrderServices.hasPermission(orderId, userLogin, "UPDATE", security, delegator);
    if (!hasPermission) {
        return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
                "OrderYouDoNotHavePermissionToChangeThisOrdersStatus", locale));
    }/*from ww w .  j  a  v a2  s.  c om*/

    // get the order header
    GenericValue orderHeader = null;
    try {
        orderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId));
    } catch (GenericEntityException e) {
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource_error, "OrderErrorCannotGetOrderHeaderEntity", locale)
                        + e.getMessage());
    }

    if (orderHeader == null) {
        return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
                "OrderErrorNoValidOrderHeaderFoundForOrderId", UtilMisc.toMap("orderId", orderId), locale));
    }

    // don't charge tax on purchase orders, better we still do.....
    //        if ("PURCHASE_ORDER".equals(orderHeader.getString("orderTypeId"))) {
    //            return ServiceUtil.returnSuccess();
    //        }

    // Retrieve the order tax adjustments
    List<GenericValue> orderTaxAdjustments = null;
    try {
        orderTaxAdjustments = delegator.findByAnd("OrderAdjustment", UtilMisc.toMap("orderId", orderId));
        orderTaxAdjustments = OrderReadHelper.fetchTaxAdjustments(orderTaxAdjustments);
    } catch (GenericEntityException e) {
        Debug.logError(e, "Unable to retrieve SALES_TAX adjustments for order : " + orderId, module);
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource_error, "OrderUnableToRetrieveSalesTaxAdjustments", locale));
    }

    // Accumulate the total existing tax adjustment
    BigDecimal totalExistingOrderTax = ZERO;
    Iterator<GenericValue> otait = UtilMisc.toIterator(orderTaxAdjustments);
    while (otait != null && otait.hasNext()) {
        GenericValue orderTaxAdjustment = otait.next();
        if (orderTaxAdjustment.get("amount") != null) {
            totalExistingOrderTax = totalExistingOrderTax
                    .add(orderTaxAdjustment.getBigDecimal("amount").setScale(taxDecimals, taxRounding));
        }
    }

    // Recalculate the taxes for the order
    BigDecimal totalNewOrderTax = ZERO;
    OrderReadHelper orh = new OrderReadHelper(orderHeader);
    List<GenericValue> shipGroups = orh.getOrderItemShipGroups();
    if (shipGroups != null) {
        Iterator<GenericValue> itr = shipGroups.iterator();
        while (itr.hasNext()) {
            GenericValue shipGroup = itr.next();
            String shipGroupSeqId = shipGroup.getString("shipGroupSeqId");

            List<GenericValue> validOrderItems = orh.getValidOrderItems(shipGroupSeqId);
            if (validOrderItems != null) {
                // prepare the inital lists
                List<GenericValue> products = new ArrayList<GenericValue>(validOrderItems.size());
                List<BigDecimal> amounts = new ArrayList<BigDecimal>(validOrderItems.size());
                List<BigDecimal> shipAmts = new ArrayList<BigDecimal>(validOrderItems.size());
                List<BigDecimal> itPrices = new ArrayList<BigDecimal>(validOrderItems.size());
                List<BigDecimal> itQuantities = new ArrayList<BigDecimal>(validOrderItems.size());

                // adjustments and total
                List<GenericValue> allAdjustments = orh.getAdjustments();
                List<GenericValue> orderHeaderAdjustments = OrderReadHelper
                        .getOrderHeaderAdjustments(allAdjustments, shipGroupSeqId);
                BigDecimal orderSubTotal = OrderReadHelper.getOrderItemsSubTotal(validOrderItems,
                        allAdjustments);

                // shipping amount
                BigDecimal orderShipping = OrderReadHelper.calcOrderAdjustments(orderHeaderAdjustments,
                        orderSubTotal, false, false, true);

                //promotions amount
                BigDecimal orderPromotions = OrderReadHelper.calcOrderPromoAdjustmentsBd(allAdjustments);

                // build up the list of tax calc service parameters
                for (int i = 0; i < validOrderItems.size(); i++) {
                    GenericValue orderItem = validOrderItems.get(i);
                    String productId = orderItem.getString("productId");
                    try {
                        products.add(i,
                                delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId", productId))); // get the product entity
                        amounts.add(i,
                                OrderReadHelper.getOrderItemSubTotal(orderItem, allAdjustments, true, false)); // get the item amount
                        shipAmts.add(i, OrderReadHelper.getOrderItemAdjustmentsTotal(orderItem, allAdjustments,
                                false, false, true)); // get the shipping amount
                        itPrices.add(i, orderItem.getBigDecimal("unitPrice"));
                        itQuantities.add(i, orderItem.getBigDecimal("quantity"));
                    } catch (GenericEntityException e) {
                        Debug.logError(e, "Cannot read order item entity : " + orderItem, module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
                                "OrderCannotReadTheOrderItemEntity", locale));
                    }
                }

                GenericValue shippingAddress = orh.getShippingAddress(shipGroupSeqId);
                // no shipping address, try the billing address
                if (shippingAddress == null) {
                    List<GenericValue> billingAddressList = orh.getBillingLocations();
                    if (billingAddressList.size() > 0) {
                        shippingAddress = billingAddressList.get(0);
                    }
                }

                // TODO and NOTE DEJ20070816: this is NOT a good way to determine if this is a face-to-face or immediatelyFulfilled order
                //this should be made consistent with the CheckOutHelper.makeTaxContext(int shipGroup, GenericValue shipAddress) method
                if (shippingAddress == null) {
                    // face-to-face order; use the facility address
                    String facilityId = orderHeader.getString("originFacilityId");
                    if (facilityId != null) {
                        GenericValue facilityContactMech = ContactMechWorker.getFacilityContactMechByPurpose(
                                delegator, facilityId,
                                UtilMisc.toList("SHIP_ORIG_LOCATION", "PRIMARY_LOCATION"));
                        if (facilityContactMech != null) {
                            try {
                                shippingAddress = delegator.findByPrimaryKey("PostalAddress", UtilMisc.toMap(
                                        "contactMechId", facilityContactMech.getString("contactMechId")));
                            } catch (GenericEntityException e) {
                                Debug.logError(e, module);
                            }
                        }
                    }
                }

                // if shippingAddress is still null then don't calculate tax; it may be an situation where no tax is applicable, or the data is bad and we don't have a way to find an address to check tax for
                if (shippingAddress == null) {
                    Debug.logWarning("Not calculating tax for Order [" + orderId
                            + "] because there is no shippingAddress, and no address on the origin facility ["
                            + orderHeader.getString("originFacilityId") + "]", module);
                    continue;
                }

                // prepare the service context
                Map<String, Object> serviceContext = UtilMisc.<String, Object>toMap("productStoreId",
                        orh.getProductStoreId(), "itemProductList", products, "itemAmountList", amounts,
                        "itemShippingList", shipAmts, "itemPriceList", itPrices, "itemQuantityList",
                        itQuantities, "orderShippingAmount", orderShipping);
                serviceContext.put("shippingAddress", shippingAddress);
                serviceContext.put("orderPromotionsAmount", orderPromotions);
                if (orh.getBillToParty() != null)
                    serviceContext.put("billToPartyId", orh.getBillToParty().getString("partyId"));
                if (orh.getBillFromParty() != null)
                    serviceContext.put("payToPartyId", orh.getBillFromParty().getString("partyId"));

                // invoke the calcTax service
                Map<String, Object> serviceResult = null;
                try {
                    serviceResult = dispatcher.runSync("calcTax", serviceContext);
                } catch (GenericServiceException e) {
                    Debug.logError(e, module);
                    return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,
                            "OrderProblemOccurredInTaxService", locale));
                }

                if (ServiceUtil.isError(serviceResult)) {
                    return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult));
                }

                // the adjustments (returned in order) from the tax service
                List<GenericValue> orderAdj = UtilGenerics.checkList(serviceResult.get("orderAdjustments"));
                List<List<GenericValue>> itemAdj = UtilGenerics.checkList(serviceResult.get("itemAdjustments"));

                // Accumulate the new tax total from the recalculated header adjustments
                if (UtilValidate.isNotEmpty(orderAdj)) {
                    Iterator<GenericValue> oai = orderAdj.iterator();
                    while (oai.hasNext()) {
                        GenericValue oa = oai.next();
                        if (oa.get("amount") != null) {
                            totalNewOrderTax = totalNewOrderTax
                                    .add(oa.getBigDecimal("amount").setScale(taxDecimals, taxRounding));
                        }

                    }
                }

                // Accumulate the new tax total from the recalculated item adjustments
                if (UtilValidate.isNotEmpty(itemAdj)) {
                    for (int i = 0; i < itemAdj.size(); i++) {
                        List<GenericValue> itemAdjustments = itemAdj.get(i);
                        Iterator<GenericValue> ida = itemAdjustments.iterator();
                        while (ida.hasNext()) {
                            GenericValue ia = ida.next();
                            if (ia.get("amount") != null) {
                                totalNewOrderTax = totalNewOrderTax
                                        .add(ia.getBigDecimal("amount").setScale(taxDecimals, taxRounding));
                            }
                        }
                    }
                }
            }
        }

        // Determine the difference between existing and new tax adjustment totals, if any
        BigDecimal orderTaxDifference = totalNewOrderTax.subtract(totalExistingOrderTax).setScale(taxDecimals,
                taxRounding);

        // If the total has changed, create an OrderAdjustment to reflect the fact
        if (orderTaxDifference.signum() != 0) {
            Map<String, Object> createOrderAdjContext = new HashMap<String, Object>();
            createOrderAdjContext.put("orderAdjustmentTypeId", "SALES_TAX");
            createOrderAdjContext.put("orderId", orderId);
            createOrderAdjContext.put("orderItemSeqId", "_NA_");
            createOrderAdjContext.put("shipGroupSeqId", "_NA_");
            createOrderAdjContext.put("description", "Tax adjustment due to order change");
            createOrderAdjContext.put("amount", orderTaxDifference);
            createOrderAdjContext.put("userLogin", userLogin);
            Map<String, Object> createOrderAdjResponse = null;
            try {
                createOrderAdjResponse = dispatcher.runSync("createOrderAdjustment", createOrderAdjContext);
            } catch (GenericServiceException e) {
                String createOrderAdjErrMsg = UtilProperties.getMessage(resource_error,
                        "OrderErrorCallingCreateOrderAdjustmentService", locale);
                Debug.logError(createOrderAdjErrMsg, module);
                return ServiceUtil.returnError(createOrderAdjErrMsg);
            }
            if (ServiceUtil.isError(createOrderAdjResponse)) {
                Debug.logError(ServiceUtil.getErrorMessage(createOrderAdjResponse), module);
                return ServiceUtil.returnError(ServiceUtil.getErrorMessage(createOrderAdjResponse));
            }
        }
    }

    return ServiceUtil.returnSuccess();
}

From source file:org.openbravo.test.costing.TestCosting.java

@Test
public void testCostingBD3() throws Exception {

    final int day0 = 0;
    final int day1 = 5;
    final int day2 = 10;
    final int day3 = 15;
    final int day4 = 20;
    final int day5 = 25;
    final int day6 = 30;
    final int day7 = 35;
    final BigDecimal price1 = new BigDecimal("120.00");
    final BigDecimal price2 = new BigDecimal("135.00");
    final BigDecimal price3 = new BigDecimal("127.50");
    final BigDecimal price4 = new BigDecimal("128.0357");
    final BigDecimal price5 = new BigDecimal("132.50");
    final BigDecimal price6 = new BigDecimal("135.00");
    final BigDecimal price7 = new BigDecimal("133.00");
    final BigDecimal quantity1 = new BigDecimal("75");
    final BigDecimal quantity2 = new BigDecimal("10");
    final BigDecimal quantity3 = new BigDecimal("50");
    final BigDecimal quantity4 = new BigDecimal("25");
    final BigDecimal quantity5 = new BigDecimal("15");

    try {//  w  ww  .java 2  s.c o m

        OBContext.setOBContext(USER_ID, ROLE_ID, CLIENT_ID, ORGANIZATION_ID);
        OBContext.setAdminMode(true);

        // Create a new product for the test
        Product product = createProduct(price1);

        // Create purchase order and book it
        Order purchaseOrder1 = createPurchaseOrder(product, price1, quantity1, day0);

        // Create purchase order and book it
        Order purchaseOrder2 = createPurchaseOrder(product, price2, quantity1, day1);

        // Create goods receipt, run costing background, post it and assert it
        ShipmentInOut goodsReceipt1 = createGoodsReceipt(purchaseOrder2, price2, quantity1, day6);

        // Create goods receipt, run costing background, post it and assert it
        ShipmentInOut goodsReceipt2 = createGoodsReceipt(purchaseOrder1, price1, quantity1, day2);

        // Create goods shipment, run costing background, post it and assert it
        ShipmentInOut goodsShipment1 = createGoodsShipment(product, price3, quantity2, day3);

        // Create goods shipment, run costing background, post it and assert it
        ShipmentInOut goodsShipment2 = createGoodsShipment(product, price4, quantity3, day4);

        // Create goods shipment, run costing background, post it and assert it
        ShipmentInOut goodsShipment3 = createGoodsShipment(product, price5, quantity4, day5);

        // Create goods shipment, run costing background, post it and assert it
        ShipmentInOut goodsShipment4 = createGoodsShipment(product, price6, quantity5, day7);

        // Run price correction background
        runPriceBackground();

        // Assert product transactions
        List<ProductTransactionAssert> productTransactionAssertList = new ArrayList<ProductTransactionAssert>();
        productTransactionAssertList.add(
                new ProductTransactionAssert(OBDal.getInstance().get(ShipmentInOut.class, goodsReceipt2.getId())
                        .getMaterialMgmtShipmentInOutLineList().get(0), price1, price1));
        productTransactionAssertList.add(new ProductTransactionAssert(OBDal.getInstance()
                .get(ShipmentInOut.class, goodsShipment1.getId()).getMaterialMgmtShipmentInOutLineList().get(0),
                price3, price1));
        productTransactionAssertList.add(new ProductTransactionAssert(OBDal.getInstance()
                .get(ShipmentInOut.class, goodsShipment2.getId()).getMaterialMgmtShipmentInOutLineList().get(0),
                price4, price1));
        productTransactionAssertList.add(new ProductTransactionAssert(OBDal.getInstance()
                .get(ShipmentInOut.class, goodsShipment3.getId()).getMaterialMgmtShipmentInOutLineList().get(0),
                price5, price1));
        productTransactionAssertList.add(
                new ProductTransactionAssert(OBDal.getInstance().get(ShipmentInOut.class, goodsReceipt1.getId())
                        .getMaterialMgmtShipmentInOutLineList().get(0), price2, price7, price2));
        productTransactionAssertList.add(new ProductTransactionAssert(OBDal.getInstance()
                .get(ShipmentInOut.class, goodsShipment4.getId()).getMaterialMgmtShipmentInOutLineList().get(0),
                price6, price6));
        assertProductTransaction(product.getId(), productTransactionAssertList);

        // Assert product costing
        List<MaterialTransaction> transactionList = getProductTransactions(product.getId());
        List<ProductCostingAssert> productCostingAssertList = new ArrayList<ProductCostingAssert>();
        productCostingAssertList
                .add(new ProductCostingAssert(transactionList.get(0), price1, price3, price1, quantity1));
        productCostingAssertList.add(new ProductCostingAssert(transactionList.get(4), price2, price2, price2,
                quantity1.subtract(quantity2)));
        assertProductCosting(product.getId(), productCostingAssertList);

        // Assert cost adjustment
        List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
        List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
        List<CostAdjustmentAssert> costAdjustmentAssertLineList1 = new ArrayList<CostAdjustmentAssert>();
        costAdjustmentAssertLineList1
                .add(new CostAdjustmentAssert(transactionList.get(0), "BDT", amount0, day2, true));
        costAdjustmentAssertList.add(costAdjustmentAssertLineList1);
        List<CostAdjustmentAssert> costAdjustmentAssertLineList2 = new ArrayList<CostAdjustmentAssert>();
        costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(1), "BDT",
                quantity2.multiply(price1).add(quantity2.multiply(price3).negate()), day3, true));
        costAdjustmentAssertList.add(costAdjustmentAssertLineList2);
        List<CostAdjustmentAssert> costAdjustmentAssertLineList3 = new ArrayList<CostAdjustmentAssert>();
        costAdjustmentAssertLineList3.add(new CostAdjustmentAssert(transactionList.get(2), "BDT",
                quantity3.multiply(price1).add(quantity3.multiply(price4).negate()), day4, true));
        costAdjustmentAssertList.add(costAdjustmentAssertLineList3);
        List<CostAdjustmentAssert> costAdjustmentAssertLineList4 = new ArrayList<CostAdjustmentAssert>();
        costAdjustmentAssertLineList4.add(new CostAdjustmentAssert(transactionList.get(3), "BDT",
                quantity4.multiply(price1).add(quantity4.multiply(price5).negate()), day5, true));
        costAdjustmentAssertLineList4.add(new CostAdjustmentAssert(transactionList.get(4), "NSC",
                quantity1.multiply(price7).add(quantity1.multiply(price2).negate()), day6, false, false));
        costAdjustmentAssertList.add(costAdjustmentAssertLineList4);
        assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);

        // Post cost adjustment 1 and assert it
        postDocument(costAdjustmentList.get(1));
        List<DocumentPostAssert> documentPostAssertList1 = new ArrayList<DocumentPostAssert>();
        documentPostAssertList1.add(new DocumentPostAssert("99900", amount0,
                quantity2.multiply(price3).add(quantity2.multiply(price1).negate()), null));
        documentPostAssertList1.add(new DocumentPostAssert("35000",
                quantity2.multiply(price3).add(quantity2.multiply(price1).negate()), amount0, null));
        CostAdjustment costAdjustment1 = OBDal.getInstance().get(CostAdjustment.class,
                costAdjustmentList.get(1).getId());
        assertDocumentPost(costAdjustment1, product.getId(), documentPostAssertList1);

        // Post cost adjustment 2 and assert it
        postDocument(costAdjustmentList.get(2));
        List<DocumentPostAssert> documentPostAssertList2 = new ArrayList<DocumentPostAssert>();
        documentPostAssertList2.add(new DocumentPostAssert("99900", amount0,
                quantity3.multiply(price4).add(quantity3.multiply(price1).negate()), null));
        documentPostAssertList2.add(new DocumentPostAssert("35000",
                quantity3.multiply(price4).add(quantity3.multiply(price1).negate()), amount0, null));
        CostAdjustment costAdjustment2 = OBDal.getInstance().get(CostAdjustment.class,
                costAdjustmentList.get(2).getId());
        assertDocumentPost(costAdjustment2, product.getId(), documentPostAssertList2);

        // Post cost adjustment 3 and assert it
        postDocument(costAdjustmentList.get(3));
        List<DocumentPostAssert> documentPostAssertList3 = new ArrayList<DocumentPostAssert>();
        documentPostAssertList3.add(new DocumentPostAssert("99900", amount0,
                quantity4.multiply(price5).add(quantity4.multiply(price1).negate()), null));
        documentPostAssertList3.add(new DocumentPostAssert("35000",
                quantity4.multiply(price5).add(quantity4.multiply(price1).negate()), amount0, null));
        documentPostAssertList3.add(new DocumentPostAssert("61000",
                quantity1.multiply(price2).add(quantity1.multiply(price7).negate()), amount0, null));
        documentPostAssertList3.add(new DocumentPostAssert("35000", amount0,
                quantity1.multiply(price2).add(quantity1.multiply(price7).negate()), null));
        CostAdjustment costAdjustment3 = OBDal.getInstance().get(CostAdjustment.class,
                costAdjustmentList.get(3).getId());
        assertDocumentPost(costAdjustment3, product.getId(), documentPostAssertList3);

        OBDal.getInstance().commitAndClose();

    } catch (Exception e) {
        System.out.println(e.getMessage());
        throw new OBException(e);
    }

    finally {
        OBContext.restorePreviousMode();
    }
}

From source file:op.allowance.PnlAllowance.java

private JPanel createContentPanel4(final Resident resident, LocalDate month) {
    final String key = getKey(resident, month);

    if (!contentmap.containsKey(key)) {

        JPanel pnlMonth = new JPanel(new VerticalLayout());

        pnlMonth.setBackground(getBG(resident, 11));
        pnlMonth.setOpaque(false);//  w  w  w  .  j av  a  2 s . c o m

        //            final String prevKey = resident.getRID() + "-" + SYSCalendar.eom(month.minusMonths(1)).getYear() + "-" + SYSCalendar.eom(month.minusMonths(1)).getMonthOfYear();
        if (!carrySums.containsKey(key)) {
            carrySums.put(key, AllowanceTools.getSUM(resident, SYSCalendar.eom(month.minusMonths(1))));
        }

        BigDecimal rowsum = carrySums.get(key);

        if (!cashmap.containsKey(key)) {
            cashmap.put(key, AllowanceTools.getMonth(resident, month.toDate()));
        }

        JLabel lblEOM = new JLabel("<html><table border=\"0\">" + "<tr>" + "<td width=\"130\" align=\"left\">"
                + DateFormat.getDateInstance().format(month.dayOfMonth().withMaximumValue().toDate()) + "</td>"
                + "<td width=\"400\" align=\"left\">" + SYSTools.xx("admin.residents.cash.endofmonth") + "</td>"
                + "<td width=\"100\" align=\"right\"></td>" + "<td width=\"100\" align=\"right\">"
                + (rowsum.compareTo(BigDecimal.ZERO) < 0 ? "<font color=\"red\">" : "") + cf.format(rowsum)
                + (rowsum.compareTo(BigDecimal.ZERO) < 0 ? "</font>" : "") + "</td>" + "</tr>" + "</table>" +

                "</font></html>");
        pnlMonth.add(lblEOM);

        for (final Allowance allowance : cashmap.get(key)) {

            String title = "<html><table border=\"0\">" + "<tr>" + "<td width=\"130\" align=\"left\">"
                    + DateFormat.getDateInstance().format(allowance.getPit()) + "</td>"
                    + "<td width=\"400\" align=\"left\">" + allowance.getText() + "</td>"
                    + "<td width=\"100\" align=\"right\">"
                    + (allowance.getAmount().compareTo(BigDecimal.ZERO) < 0 ? "<font color=\"red\">" : "")
                    + cf.format(allowance.getAmount())
                    + (allowance.getAmount().compareTo(BigDecimal.ZERO) < 0 ? "</font>" : "") + "</td>"
                    + "<td width=\"100\" align=\"right\">"
                    + (rowsum.compareTo(BigDecimal.ZERO) < 0 ? "<font color=\"red\">" : "") + cf.format(rowsum)
                    + (rowsum.compareTo(BigDecimal.ZERO) < 0 ? "</font>" : "") + "</td>" + "</tr>" + "</table>"
                    +

                    "</font></html>";

            DefaultCPTitle cptitle = new DefaultCPTitle(title, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                }
            });
            cptitle.getButton().setIcon(
                    allowance.isReplaced() || allowance.isReplacement() ? SYSConst.icon22eraser : null);

            if (OPDE.getAppInfo().isAllowedTo(InternalClassACL.UPDATE, internalClassID)) {
                /***
                 *      _____    _ _ _
                 *     | ____|__| (_) |_
                 *     |  _| / _` | | __|
                 *     | |__| (_| | | |_
                 *     |_____\__,_|_|\__|
                 *
                 */
                final JButton btnEdit = new JButton(SYSConst.icon22edit3);
                btnEdit.setPressedIcon(SYSConst.icon22edit3Pressed);
                btnEdit.setAlignmentX(Component.RIGHT_ALIGNMENT);
                btnEdit.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                btnEdit.setContentAreaFilled(false);
                btnEdit.setBorder(null);
                btnEdit.setToolTipText(SYSTools.xx("admin.residents.cash.btnedit.tooltip"));
                btnEdit.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent actionEvent) {

                        final JidePopup popupTX = new JidePopup();
                        popupTX.setMovable(false);
                        PnlTX pnlTX = getPnlTX(resident, allowance);
                        popupTX.setContentPane(pnlTX);
                        popupTX.removeExcludedComponent(pnlTX);
                        popupTX.setDefaultFocusComponent(pnlTX);

                        popupTX.setOwner(btnEdit);
                        GUITools.showPopup(popupTX, SwingConstants.WEST);

                    }
                });
                cptitle.getRight().add(btnEdit);
                // you can edit your own entries or you are a manager. once they are replaced or a replacement record, its over.
                btnEdit.setEnabled((OPDE.getAppInfo().isAllowedTo(InternalClassACL.MANAGER, internalClassID)
                        || allowance.getUser().equals(OPDE.getLogin().getUser())) && !allowance.isReplaced()
                        && !allowance.isReplacement());

                /***
                 *      _   _           _         _______  __
                 *     | | | |_ __   __| | ___   |_   _\ \/ /
                 *     | | | | '_ \ / _` |/ _ \    | |  \  /
                 *     | |_| | | | | (_| | (_) |   | |  /  \
                 *      \___/|_| |_|\__,_|\___/    |_| /_/\_\
                 *
                 */
                final JButton btnUndoTX = new JButton(SYSConst.icon22undo);
                btnUndoTX.setPressedIcon(SYSConst.icon22Pressed);
                btnUndoTX.setAlignmentX(Component.RIGHT_ALIGNMENT);
                btnUndoTX.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                btnUndoTX.setContentAreaFilled(false);
                btnUndoTX.setBorder(null);
                btnUndoTX.setToolTipText(SYSTools.xx("admin.residents.cash.btnundotx.tooltip"));
                btnUndoTX.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent actionEvent) {

                        new DlgYesNo(
                                SYSTools.xx("misc.questions.undo1") + "<br/><i>" + "<br/><i>"
                                        + allowance.getText() + "&nbsp;" + cf.format(allowance.getAmount())
                                        + "</i><br/>" + SYSTools.xx("misc.questions.undo2"),
                                SYSConst.icon48undo, new Closure() {
                                    @Override
                                    public void execute(Object answer) {
                                        if (answer.equals(JOptionPane.YES_OPTION)) {
                                            EntityManager em = OPDE.createEM();
                                            try {
                                                em.getTransaction().begin();

                                                Allowance myOldAllowance = em.merge(allowance);
                                                Allowance myCancelAllowance = em
                                                        .merge(new Allowance(myOldAllowance));
                                                em.lock(em.merge(myOldAllowance.getResident()),
                                                        LockModeType.OPTIMISTIC);
                                                em.lock(myOldAllowance, LockModeType.OPTIMISTIC);
                                                myOldAllowance.setReplacedBy(myCancelAllowance,
                                                        em.merge(OPDE.getLogin().getUser()));

                                                em.getTransaction().commit();

                                                DateTime txDate = new DateTime(myCancelAllowance.getPit());

                                                final String keyMonth = myCancelAllowance.getResident().getRID()
                                                        + "-" + txDate.getYear() + "-"
                                                        + txDate.getMonthOfYear();
                                                contentmap.remove(keyMonth);
                                                cpMap.remove(keyMonth);
                                                cashmap.get(keyMonth).remove(allowance);
                                                cashmap.get(keyMonth).add(myOldAllowance);
                                                cashmap.get(keyMonth).add(myCancelAllowance);
                                                Collections.sort(cashmap.get(keyMonth));

                                                updateCarrySums(myCancelAllowance);

                                                createCP4(myCancelAllowance.getResident());

                                                try {
                                                    cpMap.get(keyMonth).setCollapsed(false);
                                                } catch (PropertyVetoException e) {
                                                    e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
                                                }

                                                buildPanel();

                                            } catch (OptimisticLockException ole) {
                                                OPDE.warn(ole);
                                                if (em.getTransaction().isActive()) {
                                                    em.getTransaction().rollback();
                                                }
                                                if (ole.getMessage()
                                                        .indexOf("Class> entity.info.Resident") > -1) {
                                                    OPDE.getMainframe().emptyFrame();
                                                    OPDE.getMainframe().afterLogin();
                                                }
                                                OPDE.getDisplayManager()
                                                        .addSubMessage(DisplayManager.getLockMessage());
                                            } catch (Exception e) {
                                                if (em.getTransaction().isActive()) {
                                                    em.getTransaction().rollback();
                                                }
                                                OPDE.fatal(e);
                                            } finally {
                                                em.close();
                                            }
                                        }
                                    }
                                });
                    }
                });
                cptitle.getRight().add(btnUndoTX);
                btnUndoTX.setEnabled(!allowance.isReplaced() && !allowance.isReplacement());
            }

            if (OPDE.getAppInfo().isAllowedTo(InternalClassACL.DELETE, internalClassID)) {
                /***
                 *      ____       _      _
                 *     |  _ \  ___| | ___| |_ ___
                 *     | | | |/ _ \ |/ _ \ __/ _ \
                 *     | |_| |  __/ |  __/ ||  __/
                 *     |____/ \___|_|\___|\__\___|
                 *
                 */
                final JButton btnDelete = new JButton(SYSConst.icon22delete);
                btnDelete.setPressedIcon(SYSConst.icon22deletePressed);
                btnDelete.setAlignmentX(Component.RIGHT_ALIGNMENT);
                btnDelete.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                btnDelete.setContentAreaFilled(false);
                btnDelete.setBorder(null);
                btnDelete.setToolTipText(SYSTools.xx("admin.residents.cash.btndelete.tooltip"));
                btnDelete.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent actionEvent) {
                        new DlgYesNo(
                                SYSTools.xx("misc.questions.delete1") + "<br/><i>" + allowance.getText()
                                        + "&nbsp;" + cf.format(allowance.getAmount()) + "</i><br/>"
                                        + SYSTools.xx("misc.questions.delete2"),
                                SYSConst.icon48delete, new Closure() {
                                    @Override
                                    public void execute(Object answer) {
                                        if (answer.equals(JOptionPane.YES_OPTION)) {
                                            EntityManager em = OPDE.createEM();
                                            try {
                                                em.getTransaction().begin();
                                                Allowance myAllowance = em.merge(allowance);
                                                em.lock(em.merge(myAllowance.getResident()),
                                                        LockModeType.OPTIMISTIC);

                                                Allowance theOtherOne = null;
                                                // Check for special cases
                                                if (myAllowance.isReplacement()) {
                                                    theOtherOne = em.merge(myAllowance.getReplacementFor());
                                                    theOtherOne.setReplacedBy(null);
                                                    theOtherOne.setEditedBy(null);
                                                    myAllowance.setEditPit(null);
                                                }
                                                if (myAllowance.isReplaced()) {
                                                    theOtherOne = em.merge(myAllowance.getReplacedBy());
                                                    theOtherOne.setReplacementFor(null);
                                                }

                                                em.remove(myAllowance);
                                                em.getTransaction().commit();

                                                DateTime txDate = new DateTime(myAllowance.getPit());
                                                final String keyMonth = myAllowance.getResident().getRID() + "-"
                                                        + txDate.getYear() + "-" + txDate.getMonthOfYear();

                                                cpMap.remove(keyMonth);
                                                cashmap.get(keyMonth).remove(myAllowance);
                                                if (theOtherOne != null) {
                                                    cashmap.get(keyMonth).remove(theOtherOne);
                                                    cashmap.get(keyMonth).add(theOtherOne);
                                                    Collections.sort(cashmap.get(keyMonth));
                                                }

                                                // only to update the carrysums. myAllowance will be discarded soon.
                                                myAllowance.setAmount(myAllowance.getAmount().negate());
                                                updateCarrySums(myAllowance);

                                                createCP4(myAllowance.getResident());

                                                try {
                                                    if (cpMap.containsKey(keyMonth)) {
                                                        cpMap.get(keyMonth).setCollapsed(false);
                                                    }
                                                } catch (PropertyVetoException e) {
                                                    e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
                                                }

                                                buildPanel();
                                            } catch (OptimisticLockException ole) {
                                                OPDE.warn(ole);
                                                if (em.getTransaction().isActive()) {
                                                    em.getTransaction().rollback();
                                                }
                                                if (ole.getMessage()
                                                        .indexOf("Class> entity.info.Resident") > -1) {
                                                    OPDE.getMainframe().emptyFrame();
                                                    OPDE.getMainframe().afterLogin();
                                                }
                                                OPDE.getDisplayManager()
                                                        .addSubMessage(DisplayManager.getLockMessage());
                                            } catch (Exception e) {
                                                if (em.getTransaction().isActive()) {
                                                    em.getTransaction().rollback();
                                                }
                                                OPDE.fatal(e);
                                            } finally {
                                                em.close();
                                            }
                                        }
                                    }
                                });
                    }
                });
                cptitle.getRight().add(btnDelete);
            }
            pnlMonth.add(cptitle.getMain());
            linemap.put(allowance, cptitle.getMain());

            rowsum = rowsum.subtract(allowance.getAmount());
        }

        JLabel lblBOM = new JLabel("<html><table border=\"0\">" + "<tr>" + "<td width=\"130\" align=\"left\">"
                + DateFormat.getDateInstance().format(month.dayOfMonth().withMinimumValue().toDate()) + "</td>"
                + "<td width=\"400\" align=\"left\">" + SYSTools.xx("admin.residents.cash.startofmonth")
                + "</td>" + "<td width=\"100\" align=\"right\"></td>" + "<td width=\"100\" align=\"right\">"
                + (rowsum.compareTo(BigDecimal.ZERO) < 0 ? "<font color=\"red\">" : "") + cf.format(rowsum)
                + (rowsum.compareTo(BigDecimal.ZERO) < 0 ? "</font>" : "") + "</td>" + "</tr>" + "</table>" +

                "</font></html>");
        lblBOM.setBackground(getBG(resident, 11));
        pnlMonth.add(lblBOM);
        contentmap.put(key, pnlMonth);
    }

    return contentmap.get(key);
}

From source file:org.ofbiz.accounting.invoice.InvoiceServices.java

public static Map<String, Object> updatePaymentApplicationDefBd(DispatchContext dctx,
        Map<String, Object> context) {
    Delegator delegator = dctx.getDelegator();
    Locale locale = (Locale) context.get("locale");

    if (DECIMALS == -1 || ROUNDING == -1) {
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource, "AccountingAritmeticPropertiesNotConfigured", locale));
    }/*from w  ww.j  a  v  a  2  s  . com*/

    if (!context.containsKey("useHighestAmount")) {
        context.put("useHighestAmount", "Y");
    }

    String defaultInvoiceProcessing = EntityUtilProperties.getPropertyValue("AccountingConfig",
            "invoiceProcessing", delegator);

    boolean debug = true; // show processing messages in the log..or not....

    // a 'y' in invoiceProssesing will reverse the default processing
    String changeProcessing = (String) context.get("invoiceProcessing");
    String invoiceId = (String) context.get("invoiceId");
    String invoiceItemSeqId = (String) context.get("invoiceItemSeqId");
    String paymentId = (String) context.get("paymentId");
    String toPaymentId = (String) context.get("toPaymentId");
    String paymentApplicationId = (String) context.get("paymentApplicationId");
    BigDecimal amountApplied = (BigDecimal) context.get("amountApplied");
    String billingAccountId = (String) context.get("billingAccountId");
    String taxAuthGeoId = (String) context.get("taxAuthGeoId");
    String useHighestAmount = (String) context.get("useHighestAmount");

    List<String> errorMessageList = FastList.newInstance();

    if (debug)
        Debug.logInfo("updatePaymentApplicationDefBd input parameters..." + " defaultInvoiceProcessing: "
                + defaultInvoiceProcessing + " changeDefaultInvoiceProcessing: " + changeProcessing
                + " useHighestAmount: " + useHighestAmount + " paymentApplicationId: " + paymentApplicationId
                + " PaymentId: " + paymentId + " InvoiceId: " + invoiceId + " InvoiceItemSeqId: "
                + invoiceItemSeqId + " BillingAccountId: " + billingAccountId + " toPaymentId: " + toPaymentId
                + " amountApplied: " + amountApplied + " TaxAuthGeoId: " + taxAuthGeoId, module);

    if (changeProcessing == null) {
        changeProcessing = "N"; // not provided, so no change
    }

    boolean invoiceProcessing = true;
    if (defaultInvoiceProcessing.equals("YY")) {
        invoiceProcessing = true;
    } else if (defaultInvoiceProcessing.equals("NN")) {
        invoiceProcessing = false;
    } else if (defaultInvoiceProcessing.equals("Y")) {
        invoiceProcessing = !"Y".equals(changeProcessing);
    } else if (defaultInvoiceProcessing.equals("N")) {
        invoiceProcessing = "Y".equals(changeProcessing);
    }

    // on a new paymentApplication check if only billing or invoice or tax
    // id is provided not 2,3... BUT a combination of billingAccountId and invoiceId is permitted - that's how you use a
    // Billing Account to pay for an Invoice
    if (paymentApplicationId == null) {
        int count = 0;
        if (invoiceId != null)
            count++;
        if (toPaymentId != null)
            count++;
        if (billingAccountId != null)
            count++;
        if (taxAuthGeoId != null)
            count++;
        if ((billingAccountId != null) && (invoiceId != null))
            count--;
        if (count != 1) {
            errorMessageList.add(UtilProperties.getMessage(resource,
                    "AccountingSpecifyInvoiceToPaymentBillingAccountTaxGeoId", locale));
        }
    }

    // avoid null pointer exceptions.
    if (amountApplied == null)
        amountApplied = ZERO;
    // makes no sense to have an item numer without an invoice number
    if (invoiceId == null)
        invoiceItemSeqId = null;

    // retrieve all information and perform checking on the retrieved info.....

    // Payment.....
    BigDecimal paymentApplyAvailable = ZERO;
    // amount available on the payment reduced by the already applied amounts
    BigDecimal amountAppliedMax = ZERO;
    // the maximum that can be applied taking payment,invoice,invoiceitem,billing account in concideration
    // if maxApplied is missing, this value can be used,
    // Payment this should be checked after the invoice checking because it is possible the currency is changed
    GenericValue payment = null;
    String currencyUomId = null;
    if (paymentId == null || paymentId.equals("")) {
        errorMessageList
                .add(UtilProperties.getMessage(resource, "AccountingPaymentIdBlankNotSupplied", locale));
    } else {
        try {
            payment = EntityQuery.use(delegator).from("Payment").where("paymentId", paymentId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }
        if (payment == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentRecordNotFound",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }
        paymentApplyAvailable = payment.getBigDecimal("amount")
                .subtract(PaymentWorker.getPaymentApplied(payment)).setScale(DECIMALS, ROUNDING);

        if (payment.getString("statusId").equals("PMNT_CANCELLED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentCancelled",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }
        if (payment.getString("statusId").equals("PMNT_CONFIRMED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentConfirmed",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }

        currencyUomId = payment.getString("currencyUomId");

        // if the amount to apply is 0 give it amount the payment still need
        // to apply
        if (amountApplied.signum() == 0) {
            amountAppliedMax = paymentApplyAvailable;
        }

    }

    // the "TO" Payment.....
    BigDecimal toPaymentApplyAvailable = ZERO;
    GenericValue toPayment = null;
    if (toPaymentId != null && !toPaymentId.equals("")) {
        try {
            toPayment = EntityQuery.use(delegator).from("Payment").where("paymentId", toPaymentId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }
        if (toPayment == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentRecordNotFound",
                    UtilMisc.toMap("paymentId", toPaymentId), locale));
        }
        toPaymentApplyAvailable = toPayment.getBigDecimal("amount")
                .subtract(PaymentWorker.getPaymentApplied(toPayment)).setScale(DECIMALS, ROUNDING);

        if (toPayment.getString("statusId").equals("PMNT_CANCELLED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentCancelled",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }
        if (toPayment.getString("statusId").equals("PMNT_CONFIRMED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentConfirmed",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }

        // if the amount to apply is less then required by the payment reduce it
        if (amountAppliedMax.compareTo(toPaymentApplyAvailable) > 0) {
            amountAppliedMax = toPaymentApplyAvailable;
        }

        if (paymentApplicationId == null) {
            // only check for new application records, update on existing records is checked in the paymentApplication section
            if (toPaymentApplyAvailable.signum() == 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentAlreadyApplied",
                        UtilMisc.toMap("paymentId", toPaymentId), locale));
            } else {
                // check here for too much application if a new record is
                // added (paymentApplicationId == null)
                if (amountApplied.compareTo(toPaymentApplyAvailable) > 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentLessRequested",
                            UtilMisc.<String, Object>toMap("paymentId", toPaymentId, "paymentApplyAvailable",
                                    toPaymentApplyAvailable, "amountApplied", amountApplied, "isoCode",
                                    currencyUomId),
                            locale));
                }
            }
        }

        // check if at least one send is the same as one receiver on the other payment
        if (!payment.getString("partyIdFrom").equals(toPayment.getString("partyIdTo"))
                && !payment.getString("partyIdTo").equals(toPayment.getString("partyIdFrom"))) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingFromPartySameToParty", locale));
        }

        if (debug)
            Debug.logInfo("toPayment info retrieved and checked...", module);
    }

    // assign payment to billing account if the invoice is assigned to this billing account
    if (invoiceId != null) {
        GenericValue invoice = null;
        try {
            invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }

        if (invoice == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceNotFound",
                    UtilMisc.toMap("invoiceId", invoiceId), locale));
        } else {
            if (invoice.getString("billingAccountId") != null) {
                billingAccountId = invoice.getString("billingAccountId");
            }
        }
    }

    // billing account
    GenericValue billingAccount = null;
    if (billingAccountId != null && !billingAccountId.equals("")) {
        try {
            billingAccount = EntityQuery.use(delegator).from("BillingAccount")
                    .where("billingAccountId", billingAccountId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }
        if (billingAccount == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingBillingAccountNotFound",
                    UtilMisc.toMap("billingAccountId", billingAccountId), locale));
        }
        // check the currency
        if (billingAccount.get("accountCurrencyUomId") != null && currencyUomId != null
                && !billingAccount.getString("accountCurrencyUomId").equals(currencyUomId)) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingBillingAccountCurrencyProblem",
                    UtilMisc.toMap("billingAccountId", billingAccountId, "accountCurrencyUomId",
                            billingAccount.getString("accountCurrencyUomId"), "paymentId", paymentId,
                            "paymentCurrencyUomId", currencyUomId),
                    locale));
        }

        if (debug)
            Debug.logInfo("Billing Account info retrieved and checked...", module);
    }

    // get the invoice (item) information
    BigDecimal invoiceApplyAvailable = ZERO;
    // amount available on the invoice reduced by the already applied amounts
    BigDecimal invoiceItemApplyAvailable = ZERO;
    // amount available on the invoiceItem reduced by the already applied amounts
    GenericValue invoice = null;
    GenericValue invoiceItem = null;
    if (invoiceId != null) {
        try {
            invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }

        if (invoice == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceNotFound",
                    UtilMisc.toMap("invoiceId", invoiceId), locale));
        } else { // check the invoice and when supplied the invoice item...

            if (invoice.getString("statusId").equals("INVOICE_CANCELLED")) {
                errorMessageList
                        .add(UtilProperties.getMessage(resource, "AccountingInvoiceCancelledCannotApplyTo",
                                UtilMisc.toMap("invoiceId", invoiceId), locale));
            }

            // check the currency
            if (currencyUomId != null && invoice.get("currencyUomId") != null
                    && !currencyUomId.equals(invoice.getString("currencyUomId"))) {
                Debug.logInfo(
                        UtilProperties.getMessage(resource, "AccountingInvoicePaymentCurrencyProblem",
                                UtilMisc.toMap("invoiceCurrency", invoice.getString("currencyUomId"),
                                        "paymentCurrency", payment.getString("currencyUomId")),
                                locale),
                        module);
                Debug.logInfo("will try to apply payment on the actualCurrency amount on payment", module);

                if (payment.get("actualCurrencyAmount") == null || payment.get("actualCurrencyUomId") == null) {
                    errorMessageList.add(
                            "Actual amounts are required in the currency of the invoice to make this work....");
                } else {
                    currencyUomId = payment.getString("actualCurrencyUomId");
                    if (!currencyUomId.equals(invoice.getString("currencyUomId"))) {
                        errorMessageList.add("actual currency on payment (" + currencyUomId
                                + ") not the same as original invoice currency ("
                                + invoice.getString("currencyUomId") + ")");
                    }
                }
                paymentApplyAvailable = payment.getBigDecimal("actualCurrencyAmount")
                        .subtract(PaymentWorker.getPaymentApplied(payment)).setScale(DECIMALS, ROUNDING);
                if (amountApplied.signum() == 0) {
                    amountAppliedMax = paymentApplyAvailable;
                }
            }

            // check if the invoice already covered by payments
            BigDecimal invoiceTotal = InvoiceWorker.getInvoiceTotal(invoice);
            invoiceApplyAvailable = InvoiceWorker.getInvoiceNotApplied(invoice);

            // adjust the amountAppliedMax value if required....
            if (invoiceApplyAvailable.compareTo(amountAppliedMax) < 0) {
                amountAppliedMax = invoiceApplyAvailable;
            }

            if (invoiceTotal.signum() == 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceTotalZero",
                        UtilMisc.toMap("invoiceId", invoiceId), locale));
            } else if (paymentApplicationId == null) {
                // only check for new records here...updates are checked in the paymentApplication section
                if (invoiceApplyAvailable.signum() == 0) {
                    errorMessageList
                            .add(UtilProperties.getMessage(resource, "AccountingInvoiceCompletelyApplied",
                                    UtilMisc.toMap("invoiceId", invoiceId), locale));
                }
                // check here for too much application if a new record(s) are
                // added (paymentApplicationId == null)
                else if (amountApplied.compareTo(invoiceApplyAvailable) > 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceLessRequested",
                            UtilMisc.<String, Object>toMap("invoiceId", invoiceId, "invoiceApplyAvailable",
                                    invoiceApplyAvailable, "amountApplied", amountApplied, "isoCode",
                                    invoice.getString("currencyUomId")),
                            locale));
                }
            }

            // check if at least one sender is the same as one receiver on the invoice
            if (!payment.getString("partyIdFrom").equals(invoice.getString("partyId"))
                    && !payment.getString("partyIdTo").equals(invoice.getString("partyIdFrom"))) {
                errorMessageList
                        .add(UtilProperties.getMessage(resource, "AccountingFromPartySameToParty", locale));
            }

            if (debug)
                Debug.logInfo("Invoice info retrieved and checked ...", module);
        }

        // if provided check the invoice item.
        if (invoiceItemSeqId != null) {
            // when itemSeqNr not provided delay checking on invoiceItemSeqId
            try {
                invoiceItem = EntityQuery.use(delegator).from("InvoiceItem")
                        .where("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId).queryOne();
            } catch (GenericEntityException e) {
                return ServiceUtil.returnError(e.getMessage());
            }

            if (invoiceItem == null) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceItemNotFound",
                        UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId), locale));
            } else {
                if (invoice.get("currencyUomId") != null && currencyUomId != null
                        && !invoice.getString("currencyUomId").equals(currencyUomId)) {
                    errorMessageList.add(UtilProperties.getMessage(resource,
                            "AccountingInvoicePaymentCurrencyProblem", UtilMisc.toMap("paymentCurrencyId",
                                    currencyUomId, "itemCurrency", invoice.getString("currencyUomId")),
                            locale));
                }

                // get the invoice item applied value
                BigDecimal quantity = null;
                if (invoiceItem.get("quantity") == null) {
                    quantity = BigDecimal.ONE;
                } else {
                    quantity = invoiceItem.getBigDecimal("quantity").setScale(DECIMALS, ROUNDING);
                }
                invoiceItemApplyAvailable = invoiceItem.getBigDecimal("amount").multiply(quantity)
                        .setScale(DECIMALS, ROUNDING)
                        .subtract(InvoiceWorker.getInvoiceItemApplied(invoiceItem));
                // check here for too much application if a new record is added
                // (paymentApplicationId == null)
                if (paymentApplicationId == null && amountApplied.compareTo(invoiceItemApplyAvailable) > 0) {
                    // new record
                    errorMessageList.add("Invoice(" + invoiceId + ") item(" + invoiceItemSeqId + ") has  "
                            + invoiceItemApplyAvailable + " to apply but " + amountApplied + " is requested\n");
                    String uomId = invoice.getString("currencyUomId");
                    errorMessageList.add(UtilProperties.getMessage(resource,
                            "AccountingInvoiceItemLessRequested",
                            UtilMisc.<String, Object>toMap("invoiceId", invoiceId, "invoiceItemSeqId",
                                    invoiceItemSeqId, "invoiceItemApplyAvailable", invoiceItemApplyAvailable,
                                    "amountApplied", amountApplied, "isoCode", uomId),
                            locale));
                }
            }
            if (debug)
                Debug.logInfo(
                        "InvoiceItem info retrieved and checked against the Invoice (currency and amounts) ...",
                        module);
        }
    }

    // check this at the end because the invoice can change the currency.......
    if (paymentApplicationId == null) {
        // only check for new application records, update on existing records is checked in the paymentApplication section
        if (paymentApplyAvailable.signum() == 0) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentAlreadyApplied",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        } else {
            // check here for too much application if a new record is
            // added (paymentApplicationId == null)
            if (amountApplied.compareTo(paymentApplyAvailable) > 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentLessRequested",
                        UtilMisc.<String, Object>toMap("paymentId", paymentId, "paymentApplyAvailable",
                                paymentApplyAvailable, "amountApplied", amountApplied, "isoCode",
                                currencyUomId),
                        locale));
            }
        }
    }

    // get the application record if the applicationId is supplied if not
    // create empty record.
    BigDecimal newInvoiceApplyAvailable = invoiceApplyAvailable;
    // amount available on the invoice taking into account if the invoiceItemnumber has changed
    BigDecimal newInvoiceItemApplyAvailable = invoiceItemApplyAvailable;
    // amount available on the invoiceItem taking into account if the itemnumber has changed
    BigDecimal newToPaymentApplyAvailable = toPaymentApplyAvailable;
    BigDecimal newPaymentApplyAvailable = paymentApplyAvailable;
    GenericValue paymentApplication = null;
    if (paymentApplicationId == null) {
        paymentApplication = delegator.makeValue("PaymentApplication");
        // prepare for creation
    } else { // retrieve existing paymentApplication
        try {
            paymentApplication = EntityQuery.use(delegator).from("PaymentApplication")
                    .where("paymentApplicationId", paymentApplicationId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }

        if (paymentApplication == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentApplicationNotFound",
                    UtilMisc.toMap("paymentApplicationId", paymentApplicationId), locale));
            paymentApplicationId = null;
        } else {

            // if both invoiceId and BillingId is entered there was
            // obviously a change
            // only take the newly entered item, same for tax authority and toPayment
            if (paymentApplication.get("invoiceId") == null && invoiceId != null) {
                billingAccountId = null;
                taxAuthGeoId = null;
                toPaymentId = null;
            } else if (paymentApplication.get("toPaymentId") == null && toPaymentId != null) {
                invoiceId = null;
                invoiceItemSeqId = null;
                taxAuthGeoId = null;
                billingAccountId = null;
            } else if (paymentApplication.get("billingAccountId") == null && billingAccountId != null) {
                invoiceId = null;
                invoiceItemSeqId = null;
                toPaymentId = null;
                taxAuthGeoId = null;
            } else if (paymentApplication.get("taxAuthGeoId") == null && taxAuthGeoId != null) {
                invoiceId = null;
                invoiceItemSeqId = null;
                toPaymentId = null;
                billingAccountId = null;
            }

            // check if the payment for too much application if an existing
            // application record is changed
            if (paymentApplyAvailable.compareTo(ZERO) == 0) {
                newPaymentApplyAvailable = paymentApplyAvailable
                        .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                        .setScale(DECIMALS, ROUNDING);
            } else {
                newPaymentApplyAvailable = paymentApplyAvailable.add(paymentApplyAvailable)
                        .subtract(amountApplied).setScale(DECIMALS, ROUNDING);
            }
            if (newPaymentApplyAvailable.compareTo(ZERO) < 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentNotEnough",
                        UtilMisc.<String, Object>toMap("paymentId", paymentId, "paymentApplyAvailable",
                                paymentApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied")),
                                "amountApplied", amountApplied),
                        locale));
            }

            if (invoiceId != null) {
                // only when we are processing an invoice on existing paymentApplication check invoice item for to much application if the invoice
                // number did not change
                if (invoiceId.equals(paymentApplication.getString("invoiceId"))) {
                    // check if both the itemNumbers are null then this is a
                    // record for the whole invoice
                    if (invoiceItemSeqId == null && paymentApplication.get("invoiceItemSeqId") == null) {
                        newInvoiceApplyAvailable = invoiceApplyAvailable
                                .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (invoiceApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList.add(UtilProperties.getMessage(resource,
                                    "AccountingInvoiceNotEnough", UtilMisc.<String, Object>toMap("tooMuch",
                                            newInvoiceApplyAvailable.negate(), "invoiceId", invoiceId),
                                    locale));
                        }
                    } else if (invoiceItemSeqId == null && paymentApplication.get("invoiceItemSeqId") != null) {
                        // check if the item number changed from a real Item number to a null value
                        newInvoiceApplyAvailable = invoiceApplyAvailable
                                .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (invoiceApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList.add(UtilProperties.getMessage(resource,
                                    "AccountingInvoiceNotEnough", UtilMisc.<String, Object>toMap("tooMuch",
                                            newInvoiceApplyAvailable.negate(), "invoiceId", invoiceId),
                                    locale));
                        }
                    } else if (invoiceItemSeqId != null && paymentApplication.get("invoiceItemSeqId") == null) {
                        // check if the item number changed from a null value to
                        // a real Item number
                        newInvoiceItemApplyAvailable = invoiceItemApplyAvailable.subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (newInvoiceItemApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList
                                    .add(UtilProperties.getMessage(resource, "AccountingItemInvoiceNotEnough",
                                            UtilMisc.<String, Object>toMap("tooMuch",
                                                    newInvoiceItemApplyAvailable.negate(), "invoiceId",
                                                    invoiceId, "invoiceItemSeqId", invoiceItemSeqId),
                                            locale));
                        }
                    } else if (invoiceItemSeqId.equals(paymentApplication.getString("invoiceItemSeqId"))) {
                        // check if the real item numbers the same
                        // item number the same numeric value
                        newInvoiceItemApplyAvailable = invoiceItemApplyAvailable
                                .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (newInvoiceItemApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList
                                    .add(UtilProperties.getMessage(resource, "AccountingItemInvoiceNotEnough",
                                            UtilMisc.<String, Object>toMap("tooMuch",
                                                    newInvoiceItemApplyAvailable.negate(), "invoiceId",
                                                    invoiceId, "invoiceItemSeqId", invoiceItemSeqId),
                                            locale));
                        }
                    } else {
                        // item number changed only check new item
                        newInvoiceItemApplyAvailable = invoiceItemApplyAvailable.add(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (newInvoiceItemApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList
                                    .add(UtilProperties.getMessage(resource, "AccountingItemInvoiceNotEnough",
                                            UtilMisc.<String, Object>toMap("tooMuch",
                                                    newInvoiceItemApplyAvailable.negate(), "invoiceId",
                                                    invoiceId, "invoiceItemSeqId", invoiceItemSeqId),
                                            locale));
                        }
                    }

                    // if the amountApplied = 0 give it the higest possible
                    // value
                    if (amountApplied.signum() == 0) {
                        if (newInvoiceItemApplyAvailable.compareTo(newPaymentApplyAvailable) < 0) {
                            amountApplied = newInvoiceItemApplyAvailable;
                            // from the item number
                        } else {
                            amountApplied = newPaymentApplyAvailable;
                            // from the payment
                        }
                    }

                    // check the invoice
                    newInvoiceApplyAvailable = invoiceApplyAvailable
                            .add(paymentApplication.getBigDecimal("amountApplied").subtract(amountApplied))
                            .setScale(DECIMALS, ROUNDING);
                    if (newInvoiceApplyAvailable.compareTo(ZERO) < 0) {
                        errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceNotEnough",
                                UtilMisc.<String, Object>toMap("tooMuch",
                                        invoiceApplyAvailable
                                                .add(paymentApplication.getBigDecimal("amountApplied"))
                                                .subtract(amountApplied),
                                        "invoiceId", invoiceId),
                                locale));
                    }
                }
            }

            // check the toPayment account when only the amountApplied has
            // changed,
            if (toPaymentId != null && toPaymentId.equals(paymentApplication.getString("toPaymentId"))) {
                newToPaymentApplyAvailable = toPaymentApplyAvailable
                        .subtract(paymentApplication.getBigDecimal("amountApplied")).add(amountApplied)
                        .setScale(DECIMALS, ROUNDING);
                if (newToPaymentApplyAvailable.compareTo(ZERO) < 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentNotEnough",
                            UtilMisc.<String, Object>toMap("paymentId", toPaymentId, "paymentApplyAvailable",
                                    newToPaymentApplyAvailable, "amountApplied", amountApplied),
                            locale));
                }
            } else if (toPaymentId != null) {
                // billing account entered number has changed so we have to
                // check the new billing account number.
                newToPaymentApplyAvailable = toPaymentApplyAvailable.add(amountApplied).setScale(DECIMALS,
                        ROUNDING);
                if (newToPaymentApplyAvailable.compareTo(ZERO) < 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentNotEnough",
                            UtilMisc.<String, Object>toMap("paymentId", toPaymentId, "paymentApplyAvailable",
                                    newToPaymentApplyAvailable, "amountApplied", amountApplied),
                            locale));
                }

            }
        }
        if (debug)
            Debug.logInfo("paymentApplication record info retrieved and checked...", module);
    }

    // show the maximumus what can be added in the payment application file.
    String toMessage = null; // prepare for success message
    if (debug) {
        String extra = "";
        if (invoiceItemSeqId != null) {
            extra = " Invoice item(" + invoiceItemSeqId + ") amount not yet applied: "
                    + newInvoiceItemApplyAvailable;
        }
        Debug.logInfo("checking finished, start processing with the following data... ", module);
        if (invoiceId != null) {
            Debug.logInfo(" Invoice(" + invoiceId + ") amount not yet applied: " + newInvoiceApplyAvailable
                    + extra + " Payment(" + paymentId + ") amount not yet applied: " + newPaymentApplyAvailable
                    + " Requested amount to apply:" + amountApplied, module);
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToInvoice",
                    UtilMisc.toMap("invoiceId", invoiceId), locale);
            if (extra.length() > 0)
                toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToInvoiceItem",
                        UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId), locale);
        }
        if (toPaymentId != null) {
            Debug.logInfo(" toPayment(" + toPaymentId + ") amount not yet applied: "
                    + newToPaymentApplyAvailable + " Payment(" + paymentId + ") amount not yet applied: "
                    + newPaymentApplyAvailable + " Requested amount to apply:" + amountApplied, module);
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToPayment",
                    UtilMisc.toMap("paymentId", toPaymentId), locale);
        }
        if (taxAuthGeoId != null) {
            Debug.logInfo(
                    " taxAuthGeoId(" + taxAuthGeoId + ")  Payment(" + paymentId + ") amount not yet applied: "
                            + newPaymentApplyAvailable + " Requested amount to apply:" + amountApplied,
                    module);
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToTax",
                    UtilMisc.toMap("taxAuthGeoId", taxAuthGeoId), locale);
        }
    }
    // if the amount to apply was not provided or was zero fill it with the maximum possible and provide information to the user
    if (amountApplied.signum() == 0 && useHighestAmount.equals("Y")) {
        amountApplied = newPaymentApplyAvailable;
        if (invoiceId != null && newInvoiceApplyAvailable.compareTo(amountApplied) < 0) {
            amountApplied = newInvoiceApplyAvailable;
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToInvoice",
                    UtilMisc.toMap("invoiceId", invoiceId), locale);
        }
        if (toPaymentId != null && newToPaymentApplyAvailable.compareTo(amountApplied) < 0) {
            amountApplied = newToPaymentApplyAvailable;
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToPayment",
                    UtilMisc.toMap("paymentId", toPaymentId), locale);
        }
    }

    String successMessage = null;
    if (amountApplied.signum() == 0) {
        errorMessageList.add(UtilProperties.getMessage(resource, "AccountingNoAmount", locale));
    } else {
        successMessage = UtilProperties.getMessage(resource, "AccountingApplicationSuccess",
                UtilMisc.<String, Object>toMap("amountApplied", amountApplied, "paymentId", paymentId,
                        "isoCode", currencyUomId, "toMessage", toMessage),
                locale);
    }
    // report error messages if any
    if (errorMessageList.size() > 0) {
        return ServiceUtil.returnError(errorMessageList);
    }

    // ============ start processing ======================
    // if the application is specified it is easy, update the existing record only
    if (paymentApplicationId != null) {
        // record is already retrieved previously
        if (debug)
            Debug.logInfo("Process an existing paymentApplication record: " + paymentApplicationId, module);
        // update the current record
        paymentApplication.set("invoiceId", invoiceId);
        paymentApplication.set("invoiceItemSeqId", invoiceItemSeqId);
        paymentApplication.set("paymentId", paymentId);
        paymentApplication.set("toPaymentId", toPaymentId);
        paymentApplication.set("amountApplied", amountApplied);
        paymentApplication.set("billingAccountId", billingAccountId);
        paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
        return storePaymentApplication(delegator, paymentApplication, locale);
    }

    // if no invoice sequence number is provided it assumed the requested paymentAmount will be
    // spread over the invoice starting with the lowest sequence number if
    // itemprocessing is on otherwise create one record
    if (invoiceId != null && paymentId != null && (invoiceItemSeqId == null)) {
        if (invoiceProcessing) {
            // create only a single record with a null seqId
            if (debug)
                Debug.logInfo("Try to allocate the payment to the invoice as a whole", module);
            paymentApplication.set("paymentId", paymentId);
            paymentApplication.set("toPaymentId", null);
            paymentApplication.set("invoiceId", invoiceId);
            paymentApplication.set("invoiceItemSeqId", null);
            paymentApplication.set("toPaymentId", null);
            paymentApplication.set("amountApplied", amountApplied);
            paymentApplication.set("billingAccountId", billingAccountId);
            paymentApplication.set("taxAuthGeoId", null);
            if (debug)
                Debug.logInfo("creating new paymentapplication", module);
            return storePaymentApplication(delegator, paymentApplication, locale);
        } else { // spread the amount over every single item number
            if (debug)
                Debug.logInfo("Try to allocate the payment to the itemnumbers of the invoice", module);
            // get the invoice items
            List<GenericValue> invoiceItems = null;
            try {
                invoiceItems = EntityQuery.use(delegator).from("InvoiceItem").where("invoiceId", invoiceId)
                        .queryList();
            } catch (GenericEntityException e) {
                return ServiceUtil.returnError(e.getMessage());
            }
            if (invoiceItems.size() == 0) {
                errorMessageList
                        .add(UtilProperties.getMessage(resource, "AccountingNoInvoiceItemsFoundForInvoice",
                                UtilMisc.toMap("invoiceId", invoiceId), locale));
                return ServiceUtil.returnError(errorMessageList);
            } else { // we found some invoice items, start processing....
                // check if the user want to apply a smaller amount than the maximum possible on the payment
                if (amountApplied.signum() != 0 && amountApplied.compareTo(paymentApplyAvailable) < 0) {
                    paymentApplyAvailable = amountApplied;
                }
                for (GenericValue currentInvoiceItem : invoiceItems) {
                    if (paymentApplyAvailable.compareTo(ZERO) > 0) {
                        break;
                    }
                    if (debug)
                        Debug.logInfo(
                                "Start processing item: " + currentInvoiceItem.getString("invoiceItemSeqId"),
                                module);
                    BigDecimal itemQuantity = BigDecimal.ONE;
                    if (currentInvoiceItem.get("quantity") != null
                            && currentInvoiceItem.getBigDecimal("quantity").signum() != 0) {
                        itemQuantity = new BigDecimal(currentInvoiceItem.getString("quantity"))
                                .setScale(DECIMALS, ROUNDING);
                    }
                    BigDecimal itemAmount = currentInvoiceItem.getBigDecimal("amount").setScale(DECIMALS,
                            ROUNDING);
                    BigDecimal itemTotal = itemAmount.multiply(itemQuantity).setScale(DECIMALS, ROUNDING);

                    // get the application(s) already allocated to this
                    // item, if available
                    List<GenericValue> paymentApplications = null;
                    try {
                        paymentApplications = currentInvoiceItem.getRelated("PaymentApplication", null, null,
                                false);
                    } catch (GenericEntityException e) {
                        return ServiceUtil.returnError(e.getMessage());
                    }
                    BigDecimal tobeApplied = ZERO;
                    // item total amount - already applied (if any)
                    BigDecimal alreadyApplied = ZERO;
                    if (UtilValidate.isNotEmpty(paymentApplications)) {
                        // application(s) found, add them all together
                        Iterator<GenericValue> p = paymentApplications.iterator();
                        while (p.hasNext()) {
                            paymentApplication = p.next();
                            alreadyApplied = alreadyApplied.add(paymentApplication
                                    .getBigDecimal("amountApplied").setScale(DECIMALS, ROUNDING));
                        }
                        tobeApplied = itemTotal.subtract(alreadyApplied).setScale(DECIMALS, ROUNDING);
                    } else {
                        // no application connected yet
                        tobeApplied = itemTotal;
                    }
                    if (debug)
                        Debug.logInfo("tobeApplied:(" + tobeApplied + ") = " + "itemTotal(" + itemTotal
                                + ") - alreadyApplied(" + alreadyApplied
                                + ") but not more then (nonapplied) paymentAmount(" + paymentApplyAvailable
                                + ")", module);

                    if (tobeApplied.signum() == 0) {
                        // invoiceItem already fully applied so look at the next one....
                        continue;
                    }

                    if (paymentApplyAvailable.compareTo(tobeApplied) > 0) {
                        paymentApplyAvailable = paymentApplyAvailable.subtract(tobeApplied);
                    } else {
                        tobeApplied = paymentApplyAvailable;
                        paymentApplyAvailable = ZERO;
                    }

                    // create application payment record but check currency
                    // first if supplied
                    if (invoice.get("currencyUomId") != null && currencyUomId != null
                            && !invoice.getString("currencyUomId").equals(currencyUomId)) {
                        errorMessageList.add("Payment currency (" + currencyUomId + ") and invoice currency("
                                + invoice.getString("currencyUomId") + ") not the same\n");
                    } else {
                        paymentApplication.set("paymentApplicationId", null);
                        // make sure we get a new record
                        paymentApplication.set("invoiceId", invoiceId);
                        paymentApplication.set("invoiceItemSeqId",
                                currentInvoiceItem.getString("invoiceItemSeqId"));
                        paymentApplication.set("paymentId", paymentId);
                        paymentApplication.set("toPaymentId", toPaymentId);
                        paymentApplication.set("amountApplied", tobeApplied);
                        paymentApplication.set("billingAccountId", billingAccountId);
                        paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
                        storePaymentApplication(delegator, paymentApplication, locale);
                    }

                    // check if either the invoice or the payment is fully
                    // applied, when yes change the status to paid
                    // which triggers the ledger routines....
                    /*
                     * if
                     * (InvoiceWorker.getInvoiceTotal(invoice).equals(InvoiceWorker.getInvoiceApplied(invoice))) {
                     * try { dispatcher.runSync("setInvoiceStatus",
                     * UtilMisc.toMap("invoiceId",invoiceId,"statusId","INVOICE_PAID")); }
                     * catch (GenericServiceException e1) {
                     * Debug.logError(e1, "Error updating invoice status",
                     * module); } }
                     *
                     * if
                     * (payment.getBigDecimal("amount").equals(PaymentWorker.getPaymentApplied(payment))) {
                     * GenericValue appliedPayment = (GenericValue)
                     * delegator.makeValue("Payment",
                     * UtilMisc.toMap("paymentId",paymentId,"statusId","INVOICE_PAID"));
                     * try { appliedPayment.store(); } catch
                     * (GenericEntityException e) {
                     * ServiceUtil.returnError(e.getMessage()); } }
                     */
                }

                if (errorMessageList.size() > 0) {
                    return ServiceUtil.returnError(errorMessageList);
                } else {
                    if (successMessage != null) {
                        return ServiceUtil.returnSuccess(successMessage);
                    } else {
                        return ServiceUtil.returnSuccess();
                    }
                }
            }
        }
    }

    // if no paymentApplicationId supplied create a new record with the data
    // supplied...
    if (paymentApplicationId == null && amountApplied != null) {
        paymentApplication.set("paymentApplicationId", paymentApplicationId);
        paymentApplication.set("invoiceId", invoiceId);
        paymentApplication.set("invoiceItemSeqId", invoiceItemSeqId);
        paymentApplication.set("paymentId", paymentId);
        paymentApplication.set("toPaymentId", toPaymentId);
        paymentApplication.set("amountApplied", amountApplied);
        paymentApplication.set("billingAccountId", billingAccountId);
        paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
        return storePaymentApplication(delegator, paymentApplication, locale);
    }

    // should never come here...
    errorMessageList.add(
            UtilProperties.getMessage(resource, "AccountingPaymentApplicationParameterUnsuitable", locale));
    errorMessageList
            .add(UtilProperties.getMessage(resource, "AccountingPaymentApplicationParameterListUnsuitable",
                    UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId, "paymentId",
                            paymentId, "toPaymentId", toPaymentId, "paymentApplicationId", paymentApplicationId,
                            "amountApplied", amountApplied),
                    locale));
    return ServiceUtil.returnError(errorMessageList);
}

From source file:org.apache.ofbiz.accounting.invoice.InvoiceServices.java

public static Map<String, Object> updatePaymentApplicationDefBd(DispatchContext dctx,
        Map<String, Object> context) {
    Delegator delegator = dctx.getDelegator();
    Locale locale = (Locale) context.get("locale");

    if (DECIMALS == -1 || ROUNDING == -1) {
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource, "AccountingAritmeticPropertiesNotConfigured", locale));
    }/*from w w w.jav a2s  .  c om*/

    if (!context.containsKey("useHighestAmount")) {
        context.put("useHighestAmount", "Y");
    }

    String defaultInvoiceProcessing = EntityUtilProperties.getPropertyValue("accounting", "invoiceProcessing",
            delegator);

    boolean debug = true; // show processing messages in the log..or not....

    // a 'y' in invoiceProssesing will reverse the default processing
    String changeProcessing = (String) context.get("invoiceProcessing");
    String invoiceId = (String) context.get("invoiceId");
    String invoiceItemSeqId = (String) context.get("invoiceItemSeqId");
    String paymentId = (String) context.get("paymentId");
    String toPaymentId = (String) context.get("toPaymentId");
    String paymentApplicationId = (String) context.get("paymentApplicationId");
    BigDecimal amountApplied = (BigDecimal) context.get("amountApplied");
    String billingAccountId = (String) context.get("billingAccountId");
    String taxAuthGeoId = (String) context.get("taxAuthGeoId");
    String useHighestAmount = (String) context.get("useHighestAmount");

    List<String> errorMessageList = new LinkedList<String>();

    if (debug)
        Debug.logInfo("updatePaymentApplicationDefBd input parameters..." + " defaultInvoiceProcessing: "
                + defaultInvoiceProcessing + " changeDefaultInvoiceProcessing: " + changeProcessing
                + " useHighestAmount: " + useHighestAmount + " paymentApplicationId: " + paymentApplicationId
                + " PaymentId: " + paymentId + " InvoiceId: " + invoiceId + " InvoiceItemSeqId: "
                + invoiceItemSeqId + " BillingAccountId: " + billingAccountId + " toPaymentId: " + toPaymentId
                + " amountApplied: " + amountApplied + " TaxAuthGeoId: " + taxAuthGeoId, module);

    if (changeProcessing == null) {
        changeProcessing = "N"; // not provided, so no change
    }

    boolean invoiceProcessing = true;
    if (defaultInvoiceProcessing.equals("YY")) {
        invoiceProcessing = true;
    } else if (defaultInvoiceProcessing.equals("NN")) {
        invoiceProcessing = false;
    } else if (defaultInvoiceProcessing.equals("Y")) {
        invoiceProcessing = !"Y".equals(changeProcessing);
    } else if (defaultInvoiceProcessing.equals("N")) {
        invoiceProcessing = "Y".equals(changeProcessing);
    }

    // on a new paymentApplication check if only billing or invoice or tax
    // id is provided not 2,3... BUT a combination of billingAccountId and invoiceId is permitted - that's how you use a
    // Billing Account to pay for an Invoice
    if (paymentApplicationId == null) {
        int count = 0;
        if (invoiceId != null)
            count++;
        if (toPaymentId != null)
            count++;
        if (billingAccountId != null)
            count++;
        if (taxAuthGeoId != null)
            count++;
        if ((billingAccountId != null) && (invoiceId != null))
            count--;
        if (count != 1) {
            errorMessageList.add(UtilProperties.getMessage(resource,
                    "AccountingSpecifyInvoiceToPaymentBillingAccountTaxGeoId", locale));
        }
    }

    // avoid null pointer exceptions.
    if (amountApplied == null)
        amountApplied = ZERO;
    // makes no sense to have an item numer without an invoice number
    if (invoiceId == null)
        invoiceItemSeqId = null;

    // retrieve all information and perform checking on the retrieved info.....

    // Payment.....
    BigDecimal paymentApplyAvailable = ZERO;
    // amount available on the payment reduced by the already applied amounts
    BigDecimal amountAppliedMax = ZERO;
    // the maximum that can be applied taking payment,invoice,invoiceitem,billing account in concideration
    // if maxApplied is missing, this value can be used,
    // Payment this should be checked after the invoice checking because it is possible the currency is changed
    GenericValue payment = null;
    String currencyUomId = null;
    if (paymentId == null || paymentId.equals("")) {
        errorMessageList
                .add(UtilProperties.getMessage(resource, "AccountingPaymentIdBlankNotSupplied", locale));
    } else {
        try {
            payment = EntityQuery.use(delegator).from("Payment").where("paymentId", paymentId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }
        if (payment == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentRecordNotFound",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }
        paymentApplyAvailable = payment.getBigDecimal("amount")
                .subtract(PaymentWorker.getPaymentApplied(payment)).setScale(DECIMALS, ROUNDING);

        if (payment.getString("statusId").equals("PMNT_CANCELLED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentCancelled",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }
        if (payment.getString("statusId").equals("PMNT_CONFIRMED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentConfirmed",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }

        currencyUomId = payment.getString("currencyUomId");

        // if the amount to apply is 0 give it amount the payment still need
        // to apply
        if (amountApplied.signum() == 0) {
            amountAppliedMax = paymentApplyAvailable;
        }

    }

    // the "TO" Payment.....
    BigDecimal toPaymentApplyAvailable = ZERO;
    GenericValue toPayment = null;
    if (toPaymentId != null && !toPaymentId.equals("")) {
        try {
            toPayment = EntityQuery.use(delegator).from("Payment").where("paymentId", toPaymentId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }
        if (toPayment == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentRecordNotFound",
                    UtilMisc.toMap("paymentId", toPaymentId), locale));
        }
        toPaymentApplyAvailable = toPayment.getBigDecimal("amount")
                .subtract(PaymentWorker.getPaymentApplied(toPayment)).setScale(DECIMALS, ROUNDING);

        if (toPayment.getString("statusId").equals("PMNT_CANCELLED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentCancelled",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }
        if (toPayment.getString("statusId").equals("PMNT_CONFIRMED")) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentConfirmed",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        }

        // if the amount to apply is less then required by the payment reduce it
        if (amountAppliedMax.compareTo(toPaymentApplyAvailable) > 0) {
            amountAppliedMax = toPaymentApplyAvailable;
        }

        if (paymentApplicationId == null) {
            // only check for new application records, update on existing records is checked in the paymentApplication section
            if (toPaymentApplyAvailable.signum() == 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentAlreadyApplied",
                        UtilMisc.toMap("paymentId", toPaymentId), locale));
            } else {
                // check here for too much application if a new record is
                // added (paymentApplicationId == null)
                if (amountApplied.compareTo(toPaymentApplyAvailable) > 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentLessRequested",
                            UtilMisc.<String, Object>toMap("paymentId", toPaymentId, "paymentApplyAvailable",
                                    toPaymentApplyAvailable, "amountApplied", amountApplied, "isoCode",
                                    currencyUomId),
                            locale));
                }
            }
        }

        // check if at least one send is the same as one receiver on the other payment
        if (!payment.getString("partyIdFrom").equals(toPayment.getString("partyIdTo"))
                && !payment.getString("partyIdTo").equals(toPayment.getString("partyIdFrom"))) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingFromPartySameToParty", locale));
        }

        if (debug)
            Debug.logInfo("toPayment info retrieved and checked...", module);
    }

    // assign payment to billing account if the invoice is assigned to this billing account
    if (invoiceId != null) {
        GenericValue invoice = null;
        try {
            invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }

        if (invoice == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceNotFound",
                    UtilMisc.toMap("invoiceId", invoiceId), locale));
        } else {
            if (invoice.getString("billingAccountId") != null) {
                billingAccountId = invoice.getString("billingAccountId");
            }
        }
    }

    // billing account
    GenericValue billingAccount = null;
    if (billingAccountId != null && !billingAccountId.equals("")) {
        try {
            billingAccount = EntityQuery.use(delegator).from("BillingAccount")
                    .where("billingAccountId", billingAccountId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }
        if (billingAccount == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingBillingAccountNotFound",
                    UtilMisc.toMap("billingAccountId", billingAccountId), locale));
        }
        // check the currency
        if (billingAccount.get("accountCurrencyUomId") != null && currencyUomId != null
                && !billingAccount.getString("accountCurrencyUomId").equals(currencyUomId)) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingBillingAccountCurrencyProblem",
                    UtilMisc.toMap("billingAccountId", billingAccountId, "accountCurrencyUomId",
                            billingAccount.getString("accountCurrencyUomId"), "paymentId", paymentId,
                            "paymentCurrencyUomId", currencyUomId),
                    locale));
        }

        if (debug)
            Debug.logInfo("Billing Account info retrieved and checked...", module);
    }

    // get the invoice (item) information
    BigDecimal invoiceApplyAvailable = ZERO;
    // amount available on the invoice reduced by the already applied amounts
    BigDecimal invoiceItemApplyAvailable = ZERO;
    // amount available on the invoiceItem reduced by the already applied amounts
    GenericValue invoice = null;
    GenericValue invoiceItem = null;
    if (invoiceId != null) {
        try {
            invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }

        if (invoice == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceNotFound",
                    UtilMisc.toMap("invoiceId", invoiceId), locale));
        } else { // check the invoice and when supplied the invoice item...

            if (invoice.getString("statusId").equals("INVOICE_CANCELLED")) {
                errorMessageList
                        .add(UtilProperties.getMessage(resource, "AccountingInvoiceCancelledCannotApplyTo",
                                UtilMisc.toMap("invoiceId", invoiceId), locale));
            }

            // check the currency
            if (currencyUomId != null && invoice.get("currencyUomId") != null
                    && !currencyUomId.equals(invoice.getString("currencyUomId"))) {
                Debug.logInfo(
                        UtilProperties.getMessage(resource, "AccountingInvoicePaymentCurrencyProblem",
                                UtilMisc.toMap("invoiceCurrency", invoice.getString("currencyUomId"),
                                        "paymentCurrency", payment.getString("currencyUomId")),
                                locale),
                        module);
                Debug.logInfo("will try to apply payment on the actualCurrency amount on payment", module);

                if (payment.get("actualCurrencyAmount") == null || payment.get("actualCurrencyUomId") == null) {
                    errorMessageList.add(
                            "Actual amounts are required in the currency of the invoice to make this work....");
                } else {
                    currencyUomId = payment.getString("actualCurrencyUomId");
                    if (!currencyUomId.equals(invoice.getString("currencyUomId"))) {
                        errorMessageList.add("actual currency on payment (" + currencyUomId
                                + ") not the same as original invoice currency ("
                                + invoice.getString("currencyUomId") + ")");
                    }
                }
                paymentApplyAvailable = payment.getBigDecimal("actualCurrencyAmount")
                        .subtract(PaymentWorker.getPaymentApplied(payment)).setScale(DECIMALS, ROUNDING);
                if (amountApplied.signum() == 0) {
                    amountAppliedMax = paymentApplyAvailable;
                }
            }

            // check if the invoice already covered by payments
            BigDecimal invoiceTotal = InvoiceWorker.getInvoiceTotal(invoice);
            invoiceApplyAvailable = InvoiceWorker.getInvoiceNotApplied(invoice);

            // adjust the amountAppliedMax value if required....
            if (invoiceApplyAvailable.compareTo(amountAppliedMax) < 0) {
                amountAppliedMax = invoiceApplyAvailable;
            }

            if (invoiceTotal.signum() == 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceTotalZero",
                        UtilMisc.toMap("invoiceId", invoiceId), locale));
            } else if (paymentApplicationId == null) {
                // only check for new records here...updates are checked in the paymentApplication section
                if (invoiceApplyAvailable.signum() == 0) {
                    errorMessageList
                            .add(UtilProperties.getMessage(resource, "AccountingInvoiceCompletelyApplied",
                                    UtilMisc.toMap("invoiceId", invoiceId), locale));
                }
                // check here for too much application if a new record(s) are
                // added (paymentApplicationId == null)
                else if (amountApplied.compareTo(invoiceApplyAvailable) > 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceLessRequested",
                            UtilMisc.<String, Object>toMap("invoiceId", invoiceId, "invoiceApplyAvailable",
                                    invoiceApplyAvailable, "amountApplied", amountApplied, "isoCode",
                                    invoice.getString("currencyUomId")),
                            locale));
                }
            }

            // check if at least one sender is the same as one receiver on the invoice
            if (!payment.getString("partyIdFrom").equals(invoice.getString("partyId"))
                    && !payment.getString("partyIdTo").equals(invoice.getString("partyIdFrom"))) {
                errorMessageList
                        .add(UtilProperties.getMessage(resource, "AccountingFromPartySameToParty", locale));
            }

            if (debug)
                Debug.logInfo("Invoice info retrieved and checked ...", module);
        }

        // if provided check the invoice item.
        if (invoiceItemSeqId != null) {
            // when itemSeqNr not provided delay checking on invoiceItemSeqId
            try {
                invoiceItem = EntityQuery.use(delegator).from("InvoiceItem")
                        .where("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId).queryOne();
            } catch (GenericEntityException e) {
                return ServiceUtil.returnError(e.getMessage());
            }

            if (invoiceItem == null) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceItemNotFound",
                        UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId), locale));
            } else {
                if (invoice.get("currencyUomId") != null && currencyUomId != null
                        && !invoice.getString("currencyUomId").equals(currencyUomId)) {
                    errorMessageList.add(UtilProperties.getMessage(resource,
                            "AccountingInvoicePaymentCurrencyProblem", UtilMisc.toMap("paymentCurrencyId",
                                    currencyUomId, "itemCurrency", invoice.getString("currencyUomId")),
                            locale));
                }

                // get the invoice item applied value
                BigDecimal quantity = null;
                if (invoiceItem.get("quantity") == null) {
                    quantity = BigDecimal.ONE;
                } else {
                    quantity = invoiceItem.getBigDecimal("quantity").setScale(DECIMALS, ROUNDING);
                }
                invoiceItemApplyAvailable = invoiceItem.getBigDecimal("amount").multiply(quantity)
                        .setScale(DECIMALS, ROUNDING)
                        .subtract(InvoiceWorker.getInvoiceItemApplied(invoiceItem));
                // check here for too much application if a new record is added
                if (paymentApplicationId == null && amountApplied.compareTo(invoiceItemApplyAvailable) > 0) {
                    // new record
                    errorMessageList.add("Invoice(" + invoiceId + ") item(" + invoiceItemSeqId + ") has  "
                            + invoiceItemApplyAvailable + " to apply but " + amountApplied + " is requested\n");
                    String uomId = invoice.getString("currencyUomId");
                    errorMessageList.add(UtilProperties.getMessage(resource,
                            "AccountingInvoiceItemLessRequested",
                            UtilMisc.<String, Object>toMap("invoiceId", invoiceId, "invoiceItemSeqId",
                                    invoiceItemSeqId, "invoiceItemApplyAvailable", invoiceItemApplyAvailable,
                                    "amountApplied", amountApplied, "isoCode", uomId),
                            locale));
                }
            }
            if (debug)
                Debug.logInfo(
                        "InvoiceItem info retrieved and checked against the Invoice (currency and amounts) ...",
                        module);
        }
    }

    // check this at the end because the invoice can change the currency.......
    if (paymentApplicationId == null) {
        // only check for new application records, update on existing records is checked in the paymentApplication section
        if (paymentApplyAvailable.signum() == 0) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentAlreadyApplied",
                    UtilMisc.toMap("paymentId", paymentId), locale));
        } else {
            // check here for too much application if a new record is
            // added (paymentApplicationId == null)
            if (amountApplied.compareTo(paymentApplyAvailable) > 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentLessRequested",
                        UtilMisc.<String, Object>toMap("paymentId", paymentId, "paymentApplyAvailable",
                                paymentApplyAvailable, "amountApplied", amountApplied, "isoCode",
                                currencyUomId),
                        locale));
            }
        }
    }

    // get the application record if the applicationId is supplied if not
    // create empty record.
    BigDecimal newInvoiceApplyAvailable = invoiceApplyAvailable;
    // amount available on the invoice taking into account if the invoiceItemnumber has changed
    BigDecimal newInvoiceItemApplyAvailable = invoiceItemApplyAvailable;
    // amount available on the invoiceItem taking into account if the itemnumber has changed
    BigDecimal newToPaymentApplyAvailable = toPaymentApplyAvailable;
    BigDecimal newPaymentApplyAvailable = paymentApplyAvailable;
    GenericValue paymentApplication = null;
    if (paymentApplicationId == null) {
        paymentApplication = delegator.makeValue("PaymentApplication");
        // prepare for creation
    } else { // retrieve existing paymentApplication
        try {
            paymentApplication = EntityQuery.use(delegator).from("PaymentApplication")
                    .where("paymentApplicationId", paymentApplicationId).queryOne();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(e.getMessage());
        }

        if (paymentApplication == null) {
            errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentApplicationNotFound",
                    UtilMisc.toMap("paymentApplicationId", paymentApplicationId), locale));
            paymentApplicationId = null;
        } else {

            // if both invoiceId and BillingId is entered there was
            // obviously a change
            // only take the newly entered item, same for tax authority and toPayment
            if (paymentApplication.get("invoiceId") == null && invoiceId != null) {
                billingAccountId = null;
                taxAuthGeoId = null;
                toPaymentId = null;
            } else if (paymentApplication.get("toPaymentId") == null && toPaymentId != null) {
                invoiceId = null;
                invoiceItemSeqId = null;
                taxAuthGeoId = null;
                billingAccountId = null;
            } else if (paymentApplication.get("billingAccountId") == null && billingAccountId != null) {
                invoiceId = null;
                invoiceItemSeqId = null;
                toPaymentId = null;
                taxAuthGeoId = null;
            } else if (paymentApplication.get("taxAuthGeoId") == null && taxAuthGeoId != null) {
                invoiceId = null;
                invoiceItemSeqId = null;
                toPaymentId = null;
                billingAccountId = null;
            }

            // check if the payment for too much application if an existing
            // application record is changed
            if (paymentApplyAvailable.compareTo(ZERO) == 0) {
                newPaymentApplyAvailable = paymentApplyAvailable
                        .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                        .setScale(DECIMALS, ROUNDING);
            } else {
                newPaymentApplyAvailable = paymentApplyAvailable.add(paymentApplyAvailable)
                        .subtract(amountApplied).setScale(DECIMALS, ROUNDING);
            }
            if (newPaymentApplyAvailable.compareTo(ZERO) < 0) {
                errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentNotEnough",
                        UtilMisc.<String, Object>toMap("paymentId", paymentId, "paymentApplyAvailable",
                                paymentApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied")),
                                "amountApplied", amountApplied),
                        locale));
            }

            if (invoiceId != null) {
                // only when we are processing an invoice on existing paymentApplication check invoice item for to much application if the invoice
                // number did not change
                if (invoiceId.equals(paymentApplication.getString("invoiceId"))) {
                    // check if both the itemNumbers are null then this is a
                    // record for the whole invoice
                    if (invoiceItemSeqId == null && paymentApplication.get("invoiceItemSeqId") == null) {
                        newInvoiceApplyAvailable = invoiceApplyAvailable
                                .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (invoiceApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList.add(UtilProperties.getMessage(resource,
                                    "AccountingInvoiceNotEnough", UtilMisc.<String, Object>toMap("tooMuch",
                                            newInvoiceApplyAvailable.negate(), "invoiceId", invoiceId),
                                    locale));
                        }
                    } else if (invoiceItemSeqId == null && paymentApplication.get("invoiceItemSeqId") != null) {
                        // check if the item number changed from a real Item number to a null value
                        newInvoiceApplyAvailable = invoiceApplyAvailable
                                .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (invoiceApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList.add(UtilProperties.getMessage(resource,
                                    "AccountingInvoiceNotEnough", UtilMisc.<String, Object>toMap("tooMuch",
                                            newInvoiceApplyAvailable.negate(), "invoiceId", invoiceId),
                                    locale));
                        }
                    } else if (invoiceItemSeqId != null && paymentApplication.get("invoiceItemSeqId") == null) {
                        // check if the item number changed from a null value to
                        // a real Item number
                        newInvoiceItemApplyAvailable = invoiceItemApplyAvailable.subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (newInvoiceItemApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList
                                    .add(UtilProperties.getMessage(resource, "AccountingItemInvoiceNotEnough",
                                            UtilMisc.<String, Object>toMap("tooMuch",
                                                    newInvoiceItemApplyAvailable.negate(), "invoiceId",
                                                    invoiceId, "invoiceItemSeqId", invoiceItemSeqId),
                                            locale));
                        }
                    } else if (invoiceItemSeqId.equals(paymentApplication.getString("invoiceItemSeqId"))) {
                        // check if the real item numbers the same
                        // item number the same numeric value
                        newInvoiceItemApplyAvailable = invoiceItemApplyAvailable
                                .add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (newInvoiceItemApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList
                                    .add(UtilProperties.getMessage(resource, "AccountingItemInvoiceNotEnough",
                                            UtilMisc.<String, Object>toMap("tooMuch",
                                                    newInvoiceItemApplyAvailable.negate(), "invoiceId",
                                                    invoiceId, "invoiceItemSeqId", invoiceItemSeqId),
                                            locale));
                        }
                    } else {
                        // item number changed only check new item
                        newInvoiceItemApplyAvailable = invoiceItemApplyAvailable.add(amountApplied)
                                .setScale(DECIMALS, ROUNDING);
                        if (newInvoiceItemApplyAvailable.compareTo(ZERO) < 0) {
                            errorMessageList
                                    .add(UtilProperties.getMessage(resource, "AccountingItemInvoiceNotEnough",
                                            UtilMisc.<String, Object>toMap("tooMuch",
                                                    newInvoiceItemApplyAvailable.negate(), "invoiceId",
                                                    invoiceId, "invoiceItemSeqId", invoiceItemSeqId),
                                            locale));
                        }
                    }

                    // if the amountApplied = 0 give it the higest possible
                    // value
                    if (amountApplied.signum() == 0) {
                        if (newInvoiceItemApplyAvailable.compareTo(newPaymentApplyAvailable) < 0) {
                            amountApplied = newInvoiceItemApplyAvailable;
                            // from the item number
                        } else {
                            amountApplied = newPaymentApplyAvailable;
                            // from the payment
                        }
                    }

                    // check the invoice
                    newInvoiceApplyAvailable = invoiceApplyAvailable
                            .add(paymentApplication.getBigDecimal("amountApplied").subtract(amountApplied))
                            .setScale(DECIMALS, ROUNDING);
                    if (newInvoiceApplyAvailable.compareTo(ZERO) < 0) {
                        errorMessageList.add(UtilProperties.getMessage(resource, "AccountingInvoiceNotEnough",
                                UtilMisc.<String, Object>toMap("tooMuch",
                                        invoiceApplyAvailable
                                                .add(paymentApplication.getBigDecimal("amountApplied"))
                                                .subtract(amountApplied),
                                        "invoiceId", invoiceId),
                                locale));
                    }
                }
            }

            // check the toPayment account when only the amountApplied has
            // changed,
            if (toPaymentId != null && toPaymentId.equals(paymentApplication.getString("toPaymentId"))) {
                newToPaymentApplyAvailable = toPaymentApplyAvailable
                        .subtract(paymentApplication.getBigDecimal("amountApplied")).add(amountApplied)
                        .setScale(DECIMALS, ROUNDING);
                if (newToPaymentApplyAvailable.compareTo(ZERO) < 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentNotEnough",
                            UtilMisc.<String, Object>toMap("paymentId", toPaymentId, "paymentApplyAvailable",
                                    newToPaymentApplyAvailable, "amountApplied", amountApplied),
                            locale));
                }
            } else if (toPaymentId != null) {
                // billing account entered number has changed so we have to
                // check the new billing account number.
                newToPaymentApplyAvailable = toPaymentApplyAvailable.add(amountApplied).setScale(DECIMALS,
                        ROUNDING);
                if (newToPaymentApplyAvailable.compareTo(ZERO) < 0) {
                    errorMessageList.add(UtilProperties.getMessage(resource, "AccountingPaymentNotEnough",
                            UtilMisc.<String, Object>toMap("paymentId", toPaymentId, "paymentApplyAvailable",
                                    newToPaymentApplyAvailable, "amountApplied", amountApplied),
                            locale));
                }

            }
        }
        if (debug)
            Debug.logInfo("paymentApplication record info retrieved and checked...", module);
    }

    // show the maximumus what can be added in the payment application file.
    String toMessage = null; // prepare for success message
    if (debug) {
        String extra = "";
        if (invoiceItemSeqId != null) {
            extra = " Invoice item(" + invoiceItemSeqId + ") amount not yet applied: "
                    + newInvoiceItemApplyAvailable;
        }
        Debug.logInfo("checking finished, start processing with the following data... ", module);
        if (invoiceId != null) {
            Debug.logInfo(" Invoice(" + invoiceId + ") amount not yet applied: " + newInvoiceApplyAvailable
                    + extra + " Payment(" + paymentId + ") amount not yet applied: " + newPaymentApplyAvailable
                    + " Requested amount to apply:" + amountApplied, module);
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToInvoice",
                    UtilMisc.toMap("invoiceId", invoiceId), locale);
            if (extra.length() > 0)
                toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToInvoiceItem",
                        UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId), locale);
        }
        if (toPaymentId != null) {
            Debug.logInfo(" toPayment(" + toPaymentId + ") amount not yet applied: "
                    + newToPaymentApplyAvailable + " Payment(" + paymentId + ") amount not yet applied: "
                    + newPaymentApplyAvailable + " Requested amount to apply:" + amountApplied, module);
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToPayment",
                    UtilMisc.toMap("paymentId", toPaymentId), locale);
        }
        if (taxAuthGeoId != null) {
            Debug.logInfo(
                    " taxAuthGeoId(" + taxAuthGeoId + ")  Payment(" + paymentId + ") amount not yet applied: "
                            + newPaymentApplyAvailable + " Requested amount to apply:" + amountApplied,
                    module);
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToTax",
                    UtilMisc.toMap("taxAuthGeoId", taxAuthGeoId), locale);
        }
    }
    // if the amount to apply was not provided or was zero fill it with the maximum possible and provide information to the user
    if (amountApplied.signum() == 0 && useHighestAmount.equals("Y")) {
        amountApplied = newPaymentApplyAvailable;
        if (invoiceId != null && newInvoiceApplyAvailable.compareTo(amountApplied) < 0) {
            amountApplied = newInvoiceApplyAvailable;
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToInvoice",
                    UtilMisc.toMap("invoiceId", invoiceId), locale);
        }
        if (toPaymentId != null && newToPaymentApplyAvailable.compareTo(amountApplied) < 0) {
            amountApplied = newToPaymentApplyAvailable;
            toMessage = UtilProperties.getMessage(resource, "AccountingApplicationToPayment",
                    UtilMisc.toMap("paymentId", toPaymentId), locale);
        }
    }

    String successMessage = null;
    if (amountApplied.signum() == 0) {
        errorMessageList.add(UtilProperties.getMessage(resource, "AccountingNoAmount", locale));
    } else {
        successMessage = UtilProperties.getMessage(resource, "AccountingApplicationSuccess",
                UtilMisc.<String, Object>toMap("amountApplied", amountApplied, "paymentId", paymentId,
                        "isoCode", currencyUomId, "toMessage", toMessage),
                locale);
    }
    // report error messages if any
    if (errorMessageList.size() > 0) {
        return ServiceUtil.returnError(errorMessageList);
    }

    // ============ start processing ======================
    // if the application is specified it is easy, update the existing record only
    if (paymentApplicationId != null) {
        // record is already retrieved previously
        if (debug)
            Debug.logInfo("Process an existing paymentApplication record: " + paymentApplicationId, module);
        // update the current record
        paymentApplication.set("invoiceId", invoiceId);
        paymentApplication.set("invoiceItemSeqId", invoiceItemSeqId);
        paymentApplication.set("paymentId", paymentId);
        paymentApplication.set("toPaymentId", toPaymentId);
        paymentApplication.set("amountApplied", amountApplied);
        paymentApplication.set("billingAccountId", billingAccountId);
        paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
        return storePaymentApplication(delegator, paymentApplication, locale);
    }

    // if no invoice sequence number is provided it assumed the requested paymentAmount will be
    // spread over the invoice starting with the lowest sequence number if
    // itemprocessing is on otherwise create one record
    if (invoiceId != null && paymentId != null && (invoiceItemSeqId == null)) {
        if (invoiceProcessing) {
            // create only a single record with a null seqId
            if (debug)
                Debug.logInfo("Try to allocate the payment to the invoice as a whole", module);
            paymentApplication.set("paymentId", paymentId);
            paymentApplication.set("toPaymentId", null);
            paymentApplication.set("invoiceId", invoiceId);
            paymentApplication.set("invoiceItemSeqId", null);
            paymentApplication.set("toPaymentId", null);
            paymentApplication.set("amountApplied", amountApplied);
            paymentApplication.set("billingAccountId", billingAccountId);
            paymentApplication.set("taxAuthGeoId", null);
            if (debug)
                Debug.logInfo("creating new paymentapplication", module);
            return storePaymentApplication(delegator, paymentApplication, locale);
        } else { // spread the amount over every single item number
            if (debug)
                Debug.logInfo("Try to allocate the payment to the itemnumbers of the invoice", module);
            // get the invoice items
            List<GenericValue> invoiceItems = null;
            try {
                invoiceItems = EntityQuery.use(delegator).from("InvoiceItem").where("invoiceId", invoiceId)
                        .queryList();
            } catch (GenericEntityException e) {
                return ServiceUtil.returnError(e.getMessage());
            }
            if (invoiceItems.size() == 0) {
                errorMessageList
                        .add(UtilProperties.getMessage(resource, "AccountingNoInvoiceItemsFoundForInvoice",
                                UtilMisc.toMap("invoiceId", invoiceId), locale));
                return ServiceUtil.returnError(errorMessageList);
            } else { // we found some invoice items, start processing....
                // check if the user want to apply a smaller amount than the maximum possible on the payment
                if (amountApplied.signum() != 0 && amountApplied.compareTo(paymentApplyAvailable) < 0) {
                    paymentApplyAvailable = amountApplied;
                }
                for (GenericValue currentInvoiceItem : invoiceItems) {
                    if (paymentApplyAvailable.compareTo(ZERO) > 0) {
                        break;
                    }
                    if (debug)
                        Debug.logInfo(
                                "Start processing item: " + currentInvoiceItem.getString("invoiceItemSeqId"),
                                module);
                    BigDecimal itemQuantity = BigDecimal.ONE;
                    if (currentInvoiceItem.get("quantity") != null
                            && currentInvoiceItem.getBigDecimal("quantity").signum() != 0) {
                        itemQuantity = new BigDecimal(currentInvoiceItem.getString("quantity"))
                                .setScale(DECIMALS, ROUNDING);
                    }
                    BigDecimal itemAmount = currentInvoiceItem.getBigDecimal("amount").setScale(DECIMALS,
                            ROUNDING);
                    BigDecimal itemTotal = itemAmount.multiply(itemQuantity).setScale(DECIMALS, ROUNDING);

                    // get the application(s) already allocated to this
                    // item, if available
                    List<GenericValue> paymentApplications = null;
                    try {
                        paymentApplications = currentInvoiceItem.getRelated("PaymentApplication", null, null,
                                false);
                    } catch (GenericEntityException e) {
                        return ServiceUtil.returnError(e.getMessage());
                    }
                    BigDecimal tobeApplied = ZERO;
                    // item total amount - already applied (if any)
                    BigDecimal alreadyApplied = ZERO;
                    if (UtilValidate.isNotEmpty(paymentApplications)) {
                        // application(s) found, add them all together
                        Iterator<GenericValue> p = paymentApplications.iterator();
                        while (p.hasNext()) {
                            paymentApplication = p.next();
                            alreadyApplied = alreadyApplied.add(paymentApplication
                                    .getBigDecimal("amountApplied").setScale(DECIMALS, ROUNDING));
                        }
                        tobeApplied = itemTotal.subtract(alreadyApplied).setScale(DECIMALS, ROUNDING);
                    } else {
                        // no application connected yet
                        tobeApplied = itemTotal;
                    }
                    if (debug)
                        Debug.logInfo("tobeApplied:(" + tobeApplied + ") = " + "itemTotal(" + itemTotal
                                + ") - alreadyApplied(" + alreadyApplied
                                + ") but not more then (nonapplied) paymentAmount(" + paymentApplyAvailable
                                + ")", module);

                    if (tobeApplied.signum() == 0) {
                        // invoiceItem already fully applied so look at the next one....
                        continue;
                    }

                    if (paymentApplyAvailable.compareTo(tobeApplied) > 0) {
                        paymentApplyAvailable = paymentApplyAvailable.subtract(tobeApplied);
                    } else {
                        tobeApplied = paymentApplyAvailable;
                        paymentApplyAvailable = ZERO;
                    }

                    // create application payment record but check currency
                    // first if supplied
                    if (invoice.get("currencyUomId") != null && currencyUomId != null
                            && !invoice.getString("currencyUomId").equals(currencyUomId)) {
                        errorMessageList.add("Payment currency (" + currencyUomId + ") and invoice currency("
                                + invoice.getString("currencyUomId") + ") not the same\n");
                    } else {
                        paymentApplication.set("paymentApplicationId", null);
                        // make sure we get a new record
                        paymentApplication.set("invoiceId", invoiceId);
                        paymentApplication.set("invoiceItemSeqId",
                                currentInvoiceItem.getString("invoiceItemSeqId"));
                        paymentApplication.set("paymentId", paymentId);
                        paymentApplication.set("toPaymentId", toPaymentId);
                        paymentApplication.set("amountApplied", tobeApplied);
                        paymentApplication.set("billingAccountId", billingAccountId);
                        paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
                        storePaymentApplication(delegator, paymentApplication, locale);
                    }

                }

                if (errorMessageList.size() > 0) {
                    return ServiceUtil.returnError(errorMessageList);
                } else {
                    if (successMessage != null) {
                        return ServiceUtil.returnSuccess(successMessage);
                    } else {
                        return ServiceUtil.returnSuccess();
                    }
                }
            }
        }
    }

    // if no paymentApplicationId supplied create a new record with the data
    // supplied...
    if (paymentApplicationId == null && amountApplied != null) {
        paymentApplication.set("paymentApplicationId", paymentApplicationId);
        paymentApplication.set("invoiceId", invoiceId);
        paymentApplication.set("invoiceItemSeqId", invoiceItemSeqId);
        paymentApplication.set("paymentId", paymentId);
        paymentApplication.set("toPaymentId", toPaymentId);
        paymentApplication.set("amountApplied", amountApplied);
        paymentApplication.set("billingAccountId", billingAccountId);
        paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
        return storePaymentApplication(delegator, paymentApplication, locale);
    }

    // should never come here...
    errorMessageList.add(
            UtilProperties.getMessage(resource, "AccountingPaymentApplicationParameterUnsuitable", locale));
    errorMessageList
            .add(UtilProperties.getMessage(resource, "AccountingPaymentApplicationParameterListUnsuitable",
                    UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId, "paymentId",
                            paymentId, "toPaymentId", toPaymentId, "paymentApplicationId", paymentApplicationId,
                            "amountApplied", amountApplied),
                    locale));
    return ServiceUtil.returnError(errorMessageList);
}

From source file:org.kuali.coeus.s2sgen.impl.generate.support.PHS398TrainingBudgetV1_0Generator.java

private PHS398TrainingBudget getPHS398TrainingBudget(
        ProposalDevelopmentDocumentContract proposalDevelopmentDocument) throws S2SException {
    DevelopmentProposalContract developmentProposal = proposalDevelopmentDocument.getDevelopmentProposal();
    ProposalDevelopmentBudgetExtContract budget = s2SCommonBudgetService.getBudget(developmentProposal);

    PHS398TrainingBudget trainingBudgetType = PHS398TrainingBudget.Factory.newInstance();
    if (budget != null) {
        trainingBudgetType.setFormVersion(FormVersion.v1_0.getVersion());
        trainingBudgetType.setBudgetType(BudgetType.PROJECT);
        setOrganizationData(trainingBudgetType, developmentProposal);
    } else {//from  w  w  w . j av  a 2 s .  com
        return trainingBudgetType;
    }

    int numPeople = 0;

    BigDecimal stipendAmountOtherFull = new BigDecimal("0"), stipendAmountOtherShort = new BigDecimal("0");
    BigDecimal stipendAmountF = new BigDecimal("0"), stipendAmountJ = new BigDecimal("0");
    BigDecimal stipendAmountPreSingFull = new BigDecimal("0"), stipendAmountPreDualFull = new BigDecimal("0");
    BigDecimal stipendAmountPreSingShort = new BigDecimal("0"), stipendAmountPreDualShort = new BigDecimal("0");
    BigDecimal stipendAmount0 = new BigDecimal("0"), stipendAmount1 = new BigDecimal("0"),
            stipendAmount2 = new BigDecimal("0"), stipendAmount3 = new BigDecimal("0"),
            stipendAmount4 = new BigDecimal("0");
    BigDecimal stipendAmount5 = new BigDecimal("0"), stipendAmount6 = new BigDecimal("0"),
            stipendAmount7 = new BigDecimal("0");
    BigDecimal stipendAmountDeg0 = new BigDecimal("0"), stipendAmountDeg1 = new BigDecimal("0"),
            stipendAmountDeg2 = new BigDecimal("0"), stipendAmountDeg3 = new BigDecimal("0"),
            stipendAmountDeg4 = new BigDecimal("0");
    BigDecimal stipendAmountDeg5 = new BigDecimal("0"), stipendAmountDeg6 = new BigDecimal("0"),
            stipendAmountDeg7 = new BigDecimal("0");
    BigDecimal stipendAmountNonDeg0 = new BigDecimal("0"), stipendAmountNonDeg1 = new BigDecimal("0"),
            stipendAmountNonDeg2 = new BigDecimal("0"), stipendAmountNonDeg3 = new BigDecimal("0"),
            stipendAmountNonDeg4 = new BigDecimal("0");
    BigDecimal stipendAmountNonDeg5 = new BigDecimal("0"), stipendAmountNonDeg6 = new BigDecimal("0"),
            stipendAmountNonDeg7 = new BigDecimal("0");

    /***** cumulative stipends **/
    BigDecimal cumUndergradStipends = new BigDecimal("0"), cumPreDocSingleStipends = new BigDecimal("0"),
            cumPreDocDualStipends = new BigDecimal("0"), cumPreDocTotalStipends = new BigDecimal("0");
    BigDecimal cumPostDocNonDegStipends = new BigDecimal("0"), cumPostDocDegStipends = new BigDecimal("0"),
            cumPostDocTotalStipends = new BigDecimal("0");
    BigDecimal cumOtherStipends = new BigDecimal("0");

    /***** cumulative tuition **/
    BigDecimal cumUndergradTuition = new BigDecimal("0"), cumPreDocSingleTuition = new BigDecimal("0"),
            cumPreDocDualTuition = new BigDecimal("0"), cumPreDocTotalTuition = new BigDecimal("0");
    BigDecimal cumPostDocNonDegTuition = new BigDecimal("0"), cumPostDocDegTuition = new BigDecimal("0"),
            cumPostDocTotalTuition = new BigDecimal("0");
    BigDecimal cumOtherTuition = new BigDecimal("0");

    /********** cumulative costs **/
    BigDecimal cumTrainingCosts = new BigDecimal("0"), cumTravelCosts = new BigDecimal("0"),
            cumConsCosts = new BigDecimal("0");
    BigDecimal cumResearchTotalDirectCosts = new BigDecimal("0"),
            cumTotalOtherDirectCosts = new BigDecimal("0"), cumTotalDirectCosts = new BigDecimal("0");
    BigDecimal cumTotalIndCosts1 = new BigDecimal("0"), cumTotalIndCosts2 = new BigDecimal("0"),
            cumTotalIndCosts = new BigDecimal("0");
    BigDecimal cumTotalDirectAndIndCosts = new BigDecimal("0");

    BigDecimal researchDirectCosts = new BigDecimal("0");
    BigDecimal totalOtherDirectCostsRequested = new BigDecimal("0");
    /********************************
     * get budget periods
     *********************************/
    List<? extends BudgetPeriodContract> budgetPeriods = budget.getBudgetPeriods();
    for (BudgetPeriodContract budgetPeriod : budgetPeriods) {
        PHS398TrainingBudgetYearDataType phs398TrainingBudgetYearDataType = trainingBudgetType
                .addNewBudgetYear();
        ScaleTwoDecimal trainingTraveCost = getBudgetPeriodCost(budgetPeriod,
                ConfigurationConstants.TRAINEE_TRAVEL_COST_ELEMENTS);
        phs398TrainingBudgetYearDataType.setTraineeTravelRequested(trainingTraveCost.bigDecimalValue());
        ScaleTwoDecimal trainingCost = getBudgetPeriodCost(budgetPeriod,
                ConfigurationConstants.TRAINING_REL_COST_ELEMENTS);
        phs398TrainingBudgetYearDataType.setTrainingRelatedExpensesRequested(trainingCost.bigDecimalValue());
        ScaleTwoDecimal consTrainingCost = getBudgetPeriodCost(budgetPeriod,
                ConfigurationConstants.SUBCONTRACT_COST_ELEMENTS);
        phs398TrainingBudgetYearDataType
                .setConsortiumTrainingCostsRequested(consTrainingCost.bigDecimalValue());

        phs398TrainingBudgetYearDataType.setPostdocNonDegreeTuitionAndFeesRequested(
                getBudgetPeriodCost(budgetPeriod, ConfigurationConstants.TUITION_POSTDOC_NONDEG_COST_ELEMENTS)
                        .bigDecimalValue());
        phs398TrainingBudgetYearDataType.setPostdocDegreeTuitionAndFeesRequested(
                getBudgetPeriodCost(budgetPeriod, ConfigurationConstants.TUITION_POSTDOC_DEG_COST_ELEMENTS)
                        .bigDecimalValue());
        phs398TrainingBudgetYearDataType.setUndergraduateTuitionAndFeesRequested(
                getBudgetPeriodCost(budgetPeriod, ConfigurationConstants.TUITION_UNDERGRAD_COST_ELEMENTS)
                        .bigDecimalValue());
        phs398TrainingBudgetYearDataType.setPredocDualDegreeTuitionAndFeesRequested(
                getBudgetPeriodCost(budgetPeriod, ConfigurationConstants.TUITION_PREDOC_DUAL_DEG_COST_ELEMENTS)
                        .bigDecimalValue());
        phs398TrainingBudgetYearDataType
                .setPredocSingleDegreeTuitionAndFeesRequested(getBudgetPeriodCost(budgetPeriod,
                        ConfigurationConstants.TUITION_PREDOC_SINGLE_DEG_COST_ELEMENTS).bigDecimalValue());
        phs398TrainingBudgetYearDataType.setOtherTuitionAndFeesRequested(
                getBudgetPeriodCost(budgetPeriod, ConfigurationConstants.TUITION_OTHER_COST_ELEMENTS)
                        .bigDecimalValue());

        phs398TrainingBudgetYearDataType.setPeriodEndDate(DateUtils.toCalendar(budgetPeriod.getEndDate()));
        phs398TrainingBudgetYearDataType.setPeriodStartDate(DateUtils.toCalendar(budgetPeriod.getStartDate()));

        /******************************
         * add to cumulative amounts for tuition and costs
         ******************************/
        cumUndergradTuition = cumUndergradTuition
                .add(phs398TrainingBudgetYearDataType.getUndergraduateTuitionAndFeesRequested());
        cumPreDocSingleTuition = cumPreDocSingleTuition
                .add(phs398TrainingBudgetYearDataType.getPredocSingleDegreeTuitionAndFeesRequested());
        cumPreDocDualTuition = cumPreDocDualTuition
                .add(phs398TrainingBudgetYearDataType.getPredocDualDegreeTuitionAndFeesRequested());

        cumPostDocNonDegTuition = cumPostDocNonDegTuition
                .add(phs398TrainingBudgetYearDataType.getPostdocNonDegreeTuitionAndFeesRequested());
        cumPostDocDegTuition = cumPostDocDegTuition
                .add(phs398TrainingBudgetYearDataType.getPostdocDegreeTuitionAndFeesRequested());
        cumPostDocTotalTuition = cumPostDocNonDegTuition.add(cumPostDocDegTuition);
        cumOtherTuition = cumOtherTuition
                .add(phs398TrainingBudgetYearDataType.getOtherTuitionAndFeesRequested());
        cumTrainingCosts = cumTrainingCosts
                .add(phs398TrainingBudgetYearDataType.getTrainingRelatedExpensesRequested());
        cumTravelCosts = cumTravelCosts.add(phs398TrainingBudgetYearDataType.getTraineeTravelRequested());
        cumConsCosts = cumConsCosts.add(phs398TrainingBudgetYearDataType.getConsortiumTrainingCostsRequested());

        /************************
         * getting first two indirect cost type
         ************************/

        IndirectCostDto indirectCostInfo = s2sBudgetCalculatorService.getIndirectCosts(budget, budgetPeriod);
        List<IndirectCostDetailsDto> cvIndirectCost = indirectCostInfo.getIndirectCostDetails();
        BigDecimal totIndCosts = new BigDecimal("0");
        for (int i = 0; i < cvIndirectCost.size() & i < CV_INDIRECT_COST_LIMIT; i++) {
            IndirectCostDetailsDto indireCost = cvIndirectCost.get(i);
            totIndCosts = totIndCosts.add(indireCost.getFunds().bigDecimalValue());
            switch (i) {
            case (0):
                phs398TrainingBudgetYearDataType.setIndirectCostType1(indireCost.getCostType());
                phs398TrainingBudgetYearDataType.setIndirectCostBase1(indireCost.getBase().bigDecimalValue());
                phs398TrainingBudgetYearDataType
                        .setIndirectCostFundsRequested1(indireCost.getFunds().bigDecimalValue());
                phs398TrainingBudgetYearDataType.setIndirectCostRate1(indireCost.getRate().bigDecimalValue());
                cumTotalIndCosts1 = cumTotalIndCosts1
                        .add(phs398TrainingBudgetYearDataType.getIndirectCostFundsRequested1());
                break;
            case (1):
                phs398TrainingBudgetYearDataType.setIndirectCostType1(indireCost.getCostType());
                phs398TrainingBudgetYearDataType.setIndirectCostBase2(indireCost.getBase().bigDecimalValue());
                phs398TrainingBudgetYearDataType
                        .setIndirectCostFundsRequested2(indireCost.getFunds().bigDecimalValue());
                phs398TrainingBudgetYearDataType.setIndirectCostRate2(indireCost.getRate().bigDecimalValue());
                cumTotalIndCosts2 = cumTotalIndCosts2
                        .add(phs398TrainingBudgetYearDataType.getIndirectCostFundsRequested2());
                break;
            default:
                break;
            }

        }
        phs398TrainingBudgetYearDataType.setTotalIndirectCostsRequested(totIndCosts);

        int numPostDocLevel0, numPostDocLevel1, numPostDocLevel2, numPostDocLevel3, numPostDocLevel4 = 0;
        int numPostDocLevel5, numPostDocLevel6, numPostDocLevel7 = 0;

        Map<String, String> hmNonDegree = new HashMap<>();
        Map<String, String> hmDegree = new HashMap<>();

        hmNonDegree.put("fulllevel0", "0");
        hmNonDegree.put("fulllevel1", "0");
        hmNonDegree.put("fulllevel2", "0");
        hmNonDegree.put("fulllevel3", "0");
        hmNonDegree.put("fulllevel4", "0");
        hmNonDegree.put("fulllevel5", "0");
        hmNonDegree.put("fulllevel6", "0");
        hmNonDegree.put("fulllevel7", "0");
        hmNonDegree.put("shortlevel0", "0");
        hmNonDegree.put("shortlevel1", "0");
        hmNonDegree.put("shortlevel2", "0");
        hmNonDegree.put("shortlevel3", "0");
        hmNonDegree.put("shortlevel4", "0");
        hmNonDegree.put("shortlevel5", "0");
        hmNonDegree.put("shortlevel6", "0");
        hmNonDegree.put("shortlevel7", "0");

        /********************************************************
         * get questionnaire answers for undergrads and predocs and others
         ********************************************************/

        String answer = null;
        int preDocCountFull = 0, preDocCountShort = 0;
        int undergradFirstYearNum = 0, undergradJrNum = 0;
        BigDecimal otherShortStipends = new BigDecimal("0"), otherFullStipends = new BigDecimal("0");
        List<? extends AnswerHeaderContract> answerHeaders = findQuestionnaireWithAnswers(developmentProposal);
        if (answerHeaders != null) {
            for (AnswerHeaderContract answerHeader : answerHeaders) {
                QuestionnaireContract questionnaire = getQuestionAnswerService()
                        .findQuestionnaireById(answerHeader.getQuestionnaireId());
                List<? extends QuestionnaireQuestionContract> questionnaireQuestions = questionnaire
                        .getQuestionnaireQuestions();
                for (QuestionnaireQuestionContract questionnaireQuestion : questionnaireQuestions) {
                    AnswerContract answerBO = getAnswer(questionnaireQuestion, answerHeader);
                    answer = answerBO.getAnswer();
                    QuestionContract question = questionnaireQuestion.getQuestion();
                    if (answer != null) {
                        int answerIntVal = 0;
                        try {
                            answerIntVal = Integer.parseInt(answer);
                        } catch (NumberFormatException ex) {
                        }
                        if (isPreDocParentQuestionFromPeriodExists(questionnaireQuestion, budgetPeriod)) {
                            switch (question.getQuestionSeqId()) {
                            case 72:
                                if (answer != null)
                                    phs398TrainingBudgetYearDataType.setUndergraduateNumFullTime(answerIntVal);
                                break;
                            case 73:
                                // short term undergrad
                                if (answer != null)
                                    phs398TrainingBudgetYearDataType.setUndergraduateNumShortTerm(answerIntVal);
                                break;
                            case 74:
                                // stipends first year
                                if (answer != null)
                                    undergradFirstYearNum = undergradFirstYearNum + answerIntVal;

                                break;
                            case 75:
                                // stipends junior
                                if (answer != null)
                                    undergradJrNum = undergradJrNum + answerIntVal;

                                break;
                            case 77:
                                // full time single degree predoc
                                if (answer != null) {
                                    phs398TrainingBudgetYearDataType
                                            .setPredocSingleDegreeNumFullTime(answerIntVal);
                                    preDocCountFull = preDocCountFull + phs398TrainingBudgetYearDataType
                                            .getPredocSingleDegreeNumFullTime();
                                }
                                break;
                            case 78:
                                // short term single degree predoc
                                if (answer != null) {
                                    phs398TrainingBudgetYearDataType
                                            .setPredocSingleDegreeNumShortTerm(answerIntVal);
                                    preDocCountShort = preDocCountShort + phs398TrainingBudgetYearDataType
                                            .getPredocSingleDegreeNumShortTerm();
                                }
                                break;
                            case 79:
                                // full term dual degree predoc
                                if (answer != null) {
                                    phs398TrainingBudgetYearDataType
                                            .setPredocDualDegreeNumFullTime(answerIntVal);
                                    preDocCountFull = preDocCountFull
                                            + phs398TrainingBudgetYearDataType.getPredocDualDegreeNumFullTime();
                                }
                                break;
                            case 80:
                                // short term dual degree predoc
                                if (answer != null) {
                                    phs398TrainingBudgetYearDataType
                                            .setPredocDualDegreeNumShortTerm(answerIntVal);
                                    preDocCountShort = preDocCountShort + phs398TrainingBudgetYearDataType
                                            .getPredocDualDegreeNumShortTerm();
                                }
                                break;
                            case 95:
                                // others full term
                                if (answer != null)
                                    phs398TrainingBudgetYearDataType.setOtherNumFullTime(answerIntVal);
                                break;
                            case 97:
                                // others short term
                                if (answer != null)
                                    phs398TrainingBudgetYearDataType.setOtherNumShortTerm(answerIntVal);
                                break;
                            case 96:
                                // others full term stipend
                                if (answer != null)
                                    otherFullStipends = new BigDecimal(answer);
                                break;
                            case 98:
                                // others short term stipend
                                if (answer != null)
                                    otherShortStipends = new BigDecimal(answer);
                                break;
                            }
                        }
                        if (isPostDocParentQuestionFromPeriodExists(questionnaireQuestion, budgetPeriod,
                                FN_INDEX)) {
                            switch (question.getQuestionSeqId()) {
                            case 86:
                                // trainees at stipend level 0
                                if (answer != null)
                                    hmNonDegree.put("fulllevel0", answer);
                                break;
                            case 87:
                                // trainees at stipend level 1
                                if (answer != null)
                                    hmNonDegree.put("fulllevel1", answer);
                                break;
                            case 88:
                                // trainees at stipend level 2
                                if (answer != null)
                                    hmNonDegree.put("fulllevel2", answer);
                                break;
                            case 89:
                                // trainees at stipend level 3
                                if (answer != null)
                                    hmNonDegree.put("fulllevel3", answer);
                                break;
                            case 90:
                                // trainees at stipend level 4
                                if (answer != null)
                                    hmNonDegree.put("fulllevel4", answer);
                                break;
                            case 91:
                                // trainees at stipend level 5
                                if (answer != null)
                                    hmNonDegree.put("fulllevel5", answer);
                                break;
                            case 92:
                                // trainees at stipend level 6
                                if (answer != null)
                                    hmNonDegree.put("fulllevel6", answer);
                                break;
                            case 93:
                                // trainees at stipend level 7
                                if (answer != null)
                                    hmNonDegree.put("fulllevel7", answer);
                                break;
                            default:
                                break;
                            }
                        }
                        if (isPostDocParentQuestionFromPeriodExists(questionnaireQuestion, budgetPeriod,
                                SN_INDEX)) {
                            switch (question.getQuestionSeqId()) {
                            case 86:
                                // trainees at stipend level 0
                                if (answer != null)
                                    hmNonDegree.put("shortlevel0", answer);
                                break;
                            case 87:
                                // trainees at stipend level 1
                                if (answer != null)
                                    hmNonDegree.put("shortlevel1", answer);
                                break;
                            case 88:
                                // trainees at stipend level 2
                                if (answer != null)
                                    hmNonDegree.put("shortlevel2", answer);
                                break;
                            case 89:
                                // trainees at stipend level 3
                                if (answer != null)
                                    hmNonDegree.put("shortlevel3", answer);
                                break;
                            case 90:
                                // trainees at stipend level 4
                                if (answer != null)
                                    hmNonDegree.put("shortlevel4", answer);
                                break;
                            case 91:
                                // trainees at stipend level 5
                                if (answer != null)
                                    hmNonDegree.put("shortlevel5", answer);
                                break;
                            case 92:
                                // trainees at stipend level 6
                                if (answer != null)
                                    hmNonDegree.put("shortlevel6", answer);
                                break;
                            case 93:
                                // trainees at stipend level 7
                                if (answer != null)
                                    hmNonDegree.put("shortlevel7", answer);
                                break;
                            default:
                                break;

                            }
                        }
                    }
                }
            }
        }
        phs398TrainingBudgetYearDataType.setUndergraduateNumFirstYearSophomoreStipends(undergradFirstYearNum);
        phs398TrainingBudgetYearDataType.setUndergraduateNumJuniorSeniorStipends(undergradJrNum);
        phs398TrainingBudgetYearDataType.setOtherStipendsRequested(otherShortStipends.add(otherFullStipends));
        phs398TrainingBudgetYearDataType.setPredocTotalNumShortTerm(preDocCountShort);
        phs398TrainingBudgetYearDataType.setPredocTotalNumFullTime(preDocCountFull);
        cumOtherStipends = cumOtherStipends.add(phs398TrainingBudgetYearDataType.getOtherStipendsRequested());

        /***********************************************************
         * set post doc non degree full time total number
         ***********************************************************/

        int postDocNumNonDegreeFullTime = Integer.parseInt(hmNonDegree.get("fulllevel0"))
                + Integer.parseInt(hmNonDegree.get("fulllevel1"))
                + Integer.parseInt(hmNonDegree.get("fulllevel2"))
                + Integer.parseInt(hmNonDegree.get("fulllevel3"))
                + Integer.parseInt(hmNonDegree.get("fulllevel4"))
                + Integer.parseInt(hmNonDegree.get("fulllevel5"))
                + Integer.parseInt(hmNonDegree.get("fulllevel6"))
                + Integer.parseInt(hmNonDegree.get("fulllevel7"));

        phs398TrainingBudgetYearDataType.setPostdocNumNonDegreeFullTime(postDocNumNonDegreeFullTime);

        /***********************************************************
         * set post doc non degree short term total number
         ***********************************************************/

        int postDocNumNonDegreeShortTerm = Integer.parseInt(hmNonDegree.get("shortlevel0"))
                + Integer.parseInt(hmNonDegree.get("shortlevel1"))
                + Integer.parseInt(hmNonDegree.get("shortlevel2"))
                + Integer.parseInt(hmNonDegree.get("shortlevel3"))
                + Integer.parseInt(hmNonDegree.get("shortlevel4"))
                + Integer.parseInt(hmNonDegree.get("shortlevel5"))
                + Integer.parseInt(hmNonDegree.get("shortlevel6"))
                + Integer.parseInt(hmNonDegree.get("shortlevel7"));

        phs398TrainingBudgetYearDataType.setPostdocNumNonDegreeShortTerm(postDocNumNonDegreeShortTerm);

        /************************************************
         * set post doc non degree level numbers
         *************************************************/
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel0(Integer.parseInt(hmNonDegree.get("fulllevel0"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel0")));

        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel1(Integer.parseInt(hmNonDegree.get("fulllevel1"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel1")));
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel2(Integer.parseInt(hmNonDegree.get("fulllevel2"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel2")));
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel3(Integer.parseInt(hmNonDegree.get("fulllevel3"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel3")));
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel4(Integer.parseInt(hmNonDegree.get("fulllevel4"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel4")));
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel5(Integer.parseInt(hmNonDegree.get("fulllevel5"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel5")));
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel6(Integer.parseInt(hmNonDegree.get("fulllevel6"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel6")));
        phs398TrainingBudgetYearDataType
                .setPostdocNumNonDegreeStipendLevel7(Integer.parseInt(hmNonDegree.get("fulllevel7"))
                        + Integer.parseInt(hmNonDegree.get("shortlevel7")));

        answer = null;

        hmDegree.put("fulllevel0", "0");
        hmDegree.put("fulllevel1", "0");
        hmDegree.put("fulllevel2", "0");
        hmDegree.put("fulllevel3", "0");
        hmDegree.put("fulllevel4", "0");
        hmDegree.put("fulllevel5", "0");
        hmDegree.put("fulllevel6", "0");
        hmDegree.put("fulllevel7", "0");
        hmDegree.put("shortlevel0", "0");
        hmDegree.put("shortlevel1", "0");
        hmDegree.put("shortlevel2", "0");
        hmDegree.put("shortlevel3", "0");
        hmDegree.put("shortlevel4", "0");
        hmDegree.put("shortlevel5", "0");
        hmDegree.put("shortlevel6", "0");
        hmDegree.put("shortlevel7", "0");
        if (answerHeaders != null) {
            for (AnswerHeaderContract answerHeader : answerHeaders) {
                QuestionnaireContract questionnaire = getQuestionAnswerService()
                        .findQuestionnaireById(answerHeader.getQuestionnaireId());
                List<? extends QuestionnaireQuestionContract> questionnaireQuestions = questionnaire
                        .getQuestionnaireQuestions();
                for (QuestionnaireQuestionContract questionnaireQuestion : questionnaireQuestions) {
                    AnswerContract answerBO = getAnswer(questionnaireQuestion, answerHeader);
                    answer = answerBO.getAnswer();
                    QuestionContract question = questionnaireQuestion.getQuestion();
                    if (answer != null) {
                        int answerIntVal = 0;
                        try {
                            answerIntVal = Integer.parseInt(answer);
                        } catch (NumberFormatException ex) {
                        }
                        if (isPostDocParentQuestionFromPeriodExists(questionnaireQuestion, budgetPeriod,
                                FD_INDEX)) {
                            switch (question.getQuestionSeqId()) {
                            case 86:
                                // trainees at stipend level 0
                                if (answer != null)
                                    hmDegree.put("fulllevel0", answer);
                                break;
                            case 87:
                                // trainees at stipend level 1
                                if (answer != null)
                                    hmDegree.put("fulllevel1", answer);
                                break;
                            case 88:
                                // trainees at stipend level 2
                                if (answer != null)
                                    hmDegree.put("fulllevel2", answer);
                                break;
                            case 89:
                                // trainees at stipend level 3
                                if (answer != null)
                                    hmDegree.put("fulllevel3", answer);
                                break;
                            case 90:
                                // trainees at stipend level 4
                                if (answer != null)
                                    hmDegree.put("fulllevel4", answer);
                                break;
                            case 91:
                                // trainees at stipend level 5
                                if (answer != null)
                                    hmDegree.put("fulllevel5", answer);
                                break;
                            case 92:
                                // trainees at stipend level 6
                                if (answer != null)
                                    hmDegree.put("fulllevel6", answer);
                                break;
                            case 93:
                                // trainees at stipend level 7
                                if (answer != null)
                                    hmDegree.put("fulllevel7", answer);
                                break;
                            default:
                                break;

                            }
                        }
                        if (isPostDocParentQuestionFromPeriodExists(questionnaireQuestion, budgetPeriod,
                                SD_INDEX)) {
                            switch (question.getQuestionSeqId()) {
                            case 86:
                                // trainees at stipend level 0
                                if (answer != null)
                                    hmDegree.put("shortlevel0", answer);
                                break;
                            case 87:
                                // trainees at stipend level 1
                                if (answer != null)
                                    hmDegree.put("shortlevel1", answer);
                                break;
                            case 88:
                                // trainees at stipend level 2
                                if (answer != null)
                                    hmDegree.put("shortlevel2", answer);
                                break;
                            case 89:
                                // trainees at stipend level 3
                                if (answer != null)
                                    hmDegree.put("shortlevel3", answer);
                                break;
                            case 90:
                                // trainees at stipend level 4
                                if (answer != null)
                                    hmDegree.put("shortlevel4", answer);
                                break;
                            case 91:
                                // trainees at stipend level 5
                                if (answer != null)
                                    hmDegree.put("shortlevel5", answer);
                                break;
                            case 92:
                                // trainees at stipend level 6
                                if (answer != null)
                                    hmDegree.put("shortlevel6", answer);
                                break;
                            case 93:
                                // trainees at stipend level 7
                                if (answer != null)
                                    hmDegree.put("shortlevel7", answer);
                                break;
                            default:
                                break;
                            }
                        }
                    }
                }
            }
        }

        /******************************************************
         * set post doc degree seeking numbers for each level
         ******************************************************/
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel0(
                Integer.parseInt(hmDegree.get("fulllevel0")) + Integer.parseInt(hmDegree.get("shortlevel0")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel1(
                Integer.parseInt(hmDegree.get("fulllevel1")) + Integer.parseInt(hmDegree.get("shortlevel1")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel2(
                Integer.parseInt(hmDegree.get("fulllevel2")) + Integer.parseInt(hmDegree.get("shortlevel2")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel3(
                Integer.parseInt(hmDegree.get("fulllevel3")) + Integer.parseInt(hmDegree.get("shortlevel3")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel4(
                Integer.parseInt(hmDegree.get("fulllevel4")) + Integer.parseInt(hmDegree.get("shortlevel4")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel5(
                Integer.parseInt(hmDegree.get("fulllevel5")) + Integer.parseInt(hmDegree.get("shortlevel5")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel6(
                Integer.parseInt(hmDegree.get("fulllevel6")) + Integer.parseInt(hmDegree.get("shortlevel6")));
        phs398TrainingBudgetYearDataType.setPostdocNumDegreeStipendLevel7(
                Integer.parseInt(hmDegree.get("fulllevel7")) + Integer.parseInt(hmDegree.get("shortlevel7")));

        /************************************************
         * set post doc degree seeking full time number
         **********************************************/

        int postDocNumDegreeFulltime = Integer.parseInt(hmDegree.get("fulllevel0"))
                + Integer.parseInt(hmDegree.get("fulllevel1")) + Integer.parseInt(hmDegree.get("fulllevel2"))
                + Integer.parseInt(hmDegree.get("fulllevel3")) + Integer.parseInt(hmDegree.get("fulllevel4"))
                + Integer.parseInt(hmDegree.get("fulllevel5")) + Integer.parseInt(hmDegree.get("fulllevel6"))
                + Integer.parseInt(hmDegree.get("fulllevel7"));

        phs398TrainingBudgetYearDataType.setPostdocNumDegreeFullTime(postDocNumDegreeFulltime);

        /***********************************************
         *set post doc degree seeking short term number
         * ************************************************/

        int postDocNumDegreeShortTerm = Integer.parseInt(hmDegree.get("shortlevel0"))
                + Integer.parseInt(hmDegree.get("shortlevel1")) + Integer.parseInt(hmDegree.get("shortlevel2"))
                + Integer.parseInt(hmDegree.get("shortlevel3")) + Integer.parseInt(hmDegree.get("shortlevel4"))
                + Integer.parseInt(hmDegree.get("shortlevel5")) + Integer.parseInt(hmDegree.get("shortlevel6"))
                + Integer.parseInt(hmDegree.get("shortlevel7"));

        phs398TrainingBudgetYearDataType.setPostdocNumDegreeShortTerm(postDocNumDegreeShortTerm);

        // Total numbers of post docs
        phs398TrainingBudgetYearDataType
                .setPostdocTotalShortTerm(phs398TrainingBudgetYearDataType.getPostdocNumDegreeShortTerm()
                        + phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeShortTerm());

        phs398TrainingBudgetYearDataType
                .setPostdocTotalFullTime(phs398TrainingBudgetYearDataType.getPostdocNumDegreeFullTime()
                        + phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeFullTime());

        // total numbers of post docs for each level
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel0(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel0()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel0());

        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel1(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel1()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel1());
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel2(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel2()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel2());
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel3(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel3()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel3());
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel4(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel4()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel4());
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel5(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel5()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel5());
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel6(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel6()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel6());
        phs398TrainingBudgetYearDataType.setPostdocTotalStipendLevel7(
                phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel7()
                        + phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel7());

        /******************************************************
         * get stipend amounts
         ******************************************************/

        // undergrad
        numPeople = phs398TrainingBudgetYearDataType.getUndergraduateNumFirstYearSophomoreStipends();
        stipendAmountF = getStipendAmount(budgetPeriod, UNDERGRADS, 0, numPeople);
        numPeople = phs398TrainingBudgetYearDataType.getUndergraduateNumJuniorSeniorStipends();
        stipendAmountJ = getStipendAmount(budgetPeriod, UNDERGRADS, 1, numPeople);
        phs398TrainingBudgetYearDataType.setUndergraduateStipendsRequested(stipendAmountF.add(stipendAmountJ));

        cumUndergradStipends = cumUndergradStipends
                .add(phs398TrainingBudgetYearDataType.getUndergraduateStipendsRequested());

        // predoc
        numPeople = phs398TrainingBudgetYearDataType.getPredocSingleDegreeNumFullTime();
        stipendAmountPreSingFull = getStipendAmount(budgetPeriod, PREDOC, 0, numPeople);
        numPeople = phs398TrainingBudgetYearDataType.getPredocDualDegreeNumFullTime();
        stipendAmountPreDualFull = getStipendAmount(budgetPeriod, PREDOC, 0, numPeople);

        numPeople = phs398TrainingBudgetYearDataType.getPredocSingleDegreeNumShortTerm();
        stipendAmountPreSingShort = getStipendAmount(budgetPeriod, PREDOC, 0, numPeople);
        numPeople = phs398TrainingBudgetYearDataType.getPredocDualDegreeNumShortTerm();
        stipendAmountPreDualShort = getStipendAmount(budgetPeriod, PREDOC, 0, numPeople);

        phs398TrainingBudgetYearDataType.setPredocSingleDegreeStipendsRequested(
                stipendAmountPreSingFull.add(stipendAmountPreSingShort));
        phs398TrainingBudgetYearDataType
                .setPredocDualDegreeStipendsRequested(stipendAmountPreDualFull.add(stipendAmountPreDualShort));
        phs398TrainingBudgetYearDataType.setPredocTotalStipendsRequested(stipendAmountPreSingFull
                .add(stipendAmountPreDualFull.add(stipendAmountPreSingShort).add(stipendAmountPreDualShort)));

        // cumulative amounts
        cumPreDocSingleStipends = cumPreDocSingleStipends.add(stipendAmountPreSingFull)
                .add(stipendAmountPreSingShort);
        cumPreDocDualStipends = cumPreDocDualStipends.add(stipendAmountPreDualFull)
                .add(stipendAmountPreDualShort);
        cumPreDocTotalStipends = cumPreDocSingleStipends.add(cumPreDocDualStipends);
        cumPreDocTotalTuition = cumPreDocDualTuition.add(cumPreDocSingleTuition);

        // postdoc

        numPostDocLevel0 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel0();
        stipendAmountNonDeg0 = getStipendAmount(budgetPeriod, POSTDOC, 0, numPostDocLevel0);
        numPostDocLevel0 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel0();
        stipendAmountDeg0 = getStipendAmount(budgetPeriod, POSTDOC, 0, numPostDocLevel0);

        numPostDocLevel1 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel1();
        stipendAmountNonDeg1 = getStipendAmount(budgetPeriod, POSTDOC, 1, numPostDocLevel1);
        numPostDocLevel1 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel1();
        stipendAmountDeg1 = getStipendAmount(budgetPeriod, POSTDOC, 1, numPostDocLevel1);

        numPostDocLevel2 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel2();
        stipendAmountNonDeg2 = getStipendAmount(budgetPeriod, POSTDOC, 2, numPostDocLevel2);
        numPostDocLevel2 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel2();
        stipendAmountDeg2 = getStipendAmount(budgetPeriod, POSTDOC, 2, numPostDocLevel2);

        numPostDocLevel3 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel3();
        stipendAmountNonDeg3 = getStipendAmount(budgetPeriod, POSTDOC, 3, numPostDocLevel3);
        numPostDocLevel3 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel3();
        stipendAmountDeg3 = getStipendAmount(budgetPeriod, POSTDOC, 3, numPostDocLevel3);

        numPostDocLevel4 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel4();
        stipendAmountNonDeg4 = getStipendAmount(budgetPeriod, POSTDOC, 4, numPostDocLevel4);
        numPostDocLevel4 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel4();
        stipendAmountDeg4 = getStipendAmount(budgetPeriod, POSTDOC, 4, numPostDocLevel4);

        numPostDocLevel5 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel5();
        stipendAmountNonDeg5 = getStipendAmount(budgetPeriod, POSTDOC, 5, numPostDocLevel5);
        numPostDocLevel5 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel5();
        stipendAmountDeg5 = getStipendAmount(budgetPeriod, POSTDOC, 5, numPostDocLevel5);

        numPostDocLevel6 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel6();
        stipendAmountNonDeg6 = getStipendAmount(budgetPeriod, POSTDOC, 6, numPostDocLevel6);
        numPostDocLevel6 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel6();
        stipendAmountDeg6 = getStipendAmount(budgetPeriod, POSTDOC, 6, numPostDocLevel6);

        numPostDocLevel7 = phs398TrainingBudgetYearDataType.getPostdocNumNonDegreeStipendLevel7();
        stipendAmountNonDeg7 = getStipendAmount(budgetPeriod, POSTDOC, 7, numPostDocLevel7);
        numPostDocLevel7 = phs398TrainingBudgetYearDataType.getPostdocNumDegreeStipendLevel7();
        stipendAmountDeg7 = getStipendAmount(budgetPeriod, POSTDOC, 7, numPostDocLevel7);

        phs398TrainingBudgetYearDataType.setPostdocDegreeStipendsRequested(stipendAmountDeg0
                .add(stipendAmountDeg1).add(stipendAmountDeg2).add(stipendAmountDeg3).add(stipendAmountDeg4)
                .add(stipendAmountDeg5).add(stipendAmountDeg6).add(stipendAmountDeg7));

        phs398TrainingBudgetYearDataType
                .setPostdocNonDegreeStipendsRequested(stipendAmountNonDeg0.add(stipendAmountNonDeg1)
                        .add(stipendAmountNonDeg2).add(stipendAmountNonDeg3).add(stipendAmountNonDeg4)
                        .add(stipendAmountNonDeg5).add(stipendAmountNonDeg6).add(stipendAmountNonDeg7));

        phs398TrainingBudgetYearDataType.setPostdocTotalStipendsRequested(
                phs398TrainingBudgetYearDataType.getPostdocNonDegreeStipendsRequested()
                        .add(phs398TrainingBudgetYearDataType.getPostdocDegreeStipendsRequested()));

        /******************************************************
         * set total amounts
         ******************************************************/

        phs398TrainingBudgetYearDataType.setPostdocTotalTuitionAndFeesRequested(
                phs398TrainingBudgetYearDataType.getPostdocDegreeTuitionAndFeesRequested()
                        .add(phs398TrainingBudgetYearDataType.getPostdocNonDegreeTuitionAndFeesRequested()));
        phs398TrainingBudgetYearDataType.setPredocTotalTuitionAndFeesRequested(
                phs398TrainingBudgetYearDataType.getPredocDualDegreeTuitionAndFeesRequested()
                        .add(phs398TrainingBudgetYearDataType.getPredocSingleDegreeTuitionAndFeesRequested()));
        phs398TrainingBudgetYearDataType.setTotalTuitionAndFeesRequested(
                phs398TrainingBudgetYearDataType.getPredocTotalTuitionAndFeesRequested()
                        .add(phs398TrainingBudgetYearDataType.getPostdocTotalTuitionAndFeesRequested().add(
                                phs398TrainingBudgetYearDataType.getUndergraduateTuitionAndFeesRequested()))
                        .add(phs398TrainingBudgetYearDataType.getOtherTuitionAndFeesRequested()));
        phs398TrainingBudgetYearDataType
                .setTotalStipendsRequested(phs398TrainingBudgetYearDataType.getPostdocTotalStipendsRequested()
                        .add(phs398TrainingBudgetYearDataType.getPredocTotalStipendsRequested()
                                .add(phs398TrainingBudgetYearDataType.getUndergraduateStipendsRequested()))
                        .add(phs398TrainingBudgetYearDataType.getOtherStipendsRequested()));
        phs398TrainingBudgetYearDataType.setTotalStipendsAndTuitionFeesRequested(
                phs398TrainingBudgetYearDataType.getTotalStipendsRequested()
                        .add(phs398TrainingBudgetYearDataType.getPostdocTotalTuitionAndFeesRequested()
                                .add(phs398TrainingBudgetYearDataType.getPredocTotalTuitionAndFeesRequested()
                                        .add(phs398TrainingBudgetYearDataType
                                                .getUndergraduateTuitionAndFeesRequested()
                                                .add(phs398TrainingBudgetYearDataType
                                                        .getOtherTuitionAndFeesRequested())))));

        // the total tdirect costs from r and r budget line, which is RESEARCH_DIRECT_COST, has to have the
        // total stipends and tuition subtracted from it.

        researchDirectCosts = budgetPeriod.getTotalDirectCost().subtract(trainingCost)
                .subtract(trainingTraveCost).subtract(consTrainingCost).bigDecimalValue();
        researchDirectCosts = researchDirectCosts
                .subtract(phs398TrainingBudgetYearDataType.getTotalStipendsAndTuitionFeesRequested());
        phs398TrainingBudgetYearDataType.setResearchDirectCostsRequested(researchDirectCosts);
        if (phs398TrainingBudgetYearDataType.getResearchDirectCostsRequested() != null) {
            Double researchDirectCostValue = phs398TrainingBudgetYearDataType.getResearchDirectCostsRequested()
                    .doubleValue();
            if (researchDirectCostValue < ZERO) {
                String researchDirectCostValueStipend = researchDirectCostValue.toString();
                String budgetYear = budgetPeriod.getBudgetPeriod().toString();
                AuditError stipendError = new AuditError(AuditError.NO_FIELD_ERROR_KEY,
                        GRANTS_GOV_STIPEND_ERROR_MESSAGE, AuditError.GG_LINK);
                String errorMessage = stipendError.getMessageKey();
                errorMessage = errorMessage.replace(STIPEND_AMOUNT, researchDirectCostValueStipend);
                errorMessage = errorMessage.replace(BUDGET_PERIOD, budgetYear);
                stipendError.setMessageKey(errorMessage);
                getAuditErrors().add(stipendError);
            }
        }

        totalOtherDirectCostsRequested = budgetPeriod.getTotalDirectCost().bigDecimalValue();
        totalOtherDirectCostsRequested = totalOtherDirectCostsRequested
                .subtract(phs398TrainingBudgetYearDataType.getTotalStipendsAndTuitionFeesRequested());
        phs398TrainingBudgetYearDataType.setTotalOtherDirectCostsRequested(totalOtherDirectCostsRequested);

        phs398TrainingBudgetYearDataType.setTotalDirectCostsRequested(
                phs398TrainingBudgetYearDataType.getTotalOtherDirectCostsRequested()
                        .add(phs398TrainingBudgetYearDataType.getTotalStipendsAndTuitionFeesRequested()));

        phs398TrainingBudgetYearDataType.setTotalDirectAndIndirectCostsRequested(
                phs398TrainingBudgetYearDataType.getTotalDirectCostsRequested()
                        .add(phs398TrainingBudgetYearDataType.getTotalIndirectCostsRequested()));

        /******************************************************
         * add to cumulative amounts
         ******************************************************/

        cumPostDocNonDegStipends = cumPostDocNonDegStipends
                .add(phs398TrainingBudgetYearDataType.getPostdocNonDegreeStipendsRequested());
        cumPostDocDegStipends = cumPostDocDegStipends
                .add(phs398TrainingBudgetYearDataType.getPostdocDegreeStipendsRequested());
        cumPostDocTotalStipends = cumPostDocNonDegStipends.add(cumPostDocDegStipends);

        cumResearchTotalDirectCosts = cumResearchTotalDirectCosts
                .add(phs398TrainingBudgetYearDataType.getResearchDirectCostsRequested());
        cumTotalOtherDirectCosts = cumTotalOtherDirectCosts
                .add(phs398TrainingBudgetYearDataType.getTotalOtherDirectCostsRequested());

    }

    // cumulative amounts
    trainingBudgetType.setCumulativeUndergraduateStipendsRequested(cumUndergradStipends);
    trainingBudgetType.setCumulativeUndergraduateTuitionAndFeesRequested(cumUndergradTuition);

    trainingBudgetType.setCumulativeOtherStipendsRequested(cumOtherStipends);
    trainingBudgetType.setCumulativeOtherTuitionAndFeesRequested(cumOtherTuition);
    trainingBudgetType.setCumulativePostdocDegreeStipendsRequested(cumPostDocDegStipends);
    trainingBudgetType.setCumulativePostdocDegreeTuitionAndFeesRequested(cumPostDocDegTuition);
    trainingBudgetType.setCumulativePostdocNonDegreeStipendsRequested(cumPostDocNonDegStipends);
    trainingBudgetType.setCumulativePostdocNonDegreeTuitionAndFeesRequested(cumPostDocNonDegTuition);
    trainingBudgetType.setCumulativePostdocTotalStipendsRequested(cumPostDocTotalStipends);
    trainingBudgetType.setCumulativePostdocTotalTuitionAndFeesRequested(cumPostDocTotalTuition);

    trainingBudgetType.setCumulativePredocDualDegreeStipendsRequested(cumPreDocDualStipends);
    trainingBudgetType.setCumulativePredocDualDegreeTuitionAndFeesRequested(cumPreDocDualTuition);
    trainingBudgetType.setCumulativePredocSingleDegreeStipendsRequested(cumPreDocSingleStipends);
    trainingBudgetType.setCumulativePredocSingleDegreeTuitionAndFeesRequested(cumPreDocSingleTuition);
    trainingBudgetType.setCumulativePredocTotalStipendsRequested(cumPreDocTotalStipends);
    trainingBudgetType.setCumulativePredocTotalTuitionAndFeesRequested(cumPreDocTotalTuition);

    trainingBudgetType.setCumulativeTotalStipendsRequested(cumPostDocTotalStipends.add(cumPreDocTotalStipends)
            .add(cumOtherStipends).add(cumUndergradStipends));

    trainingBudgetType.setCumulativeTuitionAndFeesRequested(
            cumPostDocTotalTuition.add(cumPreDocTotalTuition).add(cumOtherTuition).add(cumUndergradTuition));
    trainingBudgetType.setCumulativeTotalStipendsAndTuitionFeesRequested(
            trainingBudgetType.getCumulativeTotalStipendsRequested()
                    .add(trainingBudgetType.getCumulativeTuitionAndFeesRequested()));

    trainingBudgetType.setCumulativeConsortiumTrainingCostsRequested(cumConsCosts);
    trainingBudgetType.setCumulativeResearchDirectCostsRequested(cumResearchTotalDirectCosts);

    trainingBudgetType.setCumulativeTotalDirectCostsRequested(trainingBudgetType
            .getCumulativeTotalStipendsAndTuitionFeesRequested().add(cumTotalOtherDirectCosts));
    trainingBudgetType.setCumulativeTotalIndirectCostsRequested(cumTotalIndCosts1.add(cumTotalIndCosts2));
    trainingBudgetType.setCumulativeTotalOtherDirectCostsRequested(cumTotalOtherDirectCosts);
    trainingBudgetType.setCumulativeTotalDirectAndIndirectCostsRequested(trainingBudgetType
            .getCumulativeTotalDirectCostsRequested().add(cumTotalIndCosts1.add(cumTotalIndCosts2)));
    trainingBudgetType.setCumulativeTraineeTravelRequested(cumTravelCosts);
    trainingBudgetType.setCumulativeTrainingRelatedExpensesRequested(cumTrainingCosts);

    AttachedFileDataType attachedFileDataType = null;
    for (NarrativeContract narrative : developmentProposal.getNarratives()) {
        if (narrative.getNarrativeType().getCode() != null) {
            if (Integer.parseInt(
                    narrative.getNarrativeType().getCode()) == PHS_TRAINING_BUDGET_BUDGETJUSTIFICATION_130) {
                attachedFileDataType = getAttachedFileType(narrative);
                if (attachedFileDataType == null) {
                } else {
                    break;
                }
            }
        }
    }
    if (attachedFileDataType == null) {
        attachedFileDataType = AttachedFileDataType.Factory.newInstance();
    }
    trainingBudgetType.setBudgetJustification(attachedFileDataType);

    return trainingBudgetType;
}