Example usage for java.math BigDecimal multiply

List of usage examples for java.math BigDecimal multiply

Introduction

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

Prototype

public BigDecimal multiply(BigDecimal multiplicand) 

Source Link

Document

Returns a BigDecimal whose value is (this × multiplicand), and whose scale is (this.scale() + multiplicand.scale()) .

Usage

From source file:org.egov.ptis.domain.service.property.PropertyService.java

/**
 * Calculates penalty on tax amount//from w  w w  .j a v  a  2  s. c om
 *
 * @param latestCollReceiptDate
 * @param fromDate
 * @param amount
 * @return
 */
public BigDecimal calculatePenalty(final Date latestCollReceiptDate, final Date fromDate,
        final BigDecimal amount) {
    BigDecimal penalty;
    final int noOfMonths = PropertyTaxUtil.getMonthsBetweenDates(fromDate, new Date());
    penalty = amount.multiply(PropertyTaxConstants.PENALTY_PERCENTAGE.multiply(new BigDecimal(noOfMonths)))
            .divide(BIGDECIMAL_100);
    return MoneyUtils.roundOff(penalty);
}

From source file:com.yucheng.cmis.pvp.app.component.PvpAuthorizeComponent.java

/**
 * ??//from www  .  ja  v a 2s.  com
 * 
 * 
 * 
 * *120=
 * @param rate
 * @return
 */
public static String getCoreTradeRate(Double rate) {
    BigDecimal reality = new BigDecimal(rate);
    reality = reality.multiply(new BigDecimal(120));
    reality = reality.divide(new BigDecimal(1), 5, BigDecimal.ROUND_HALF_UP);

    return reality.toPlainString();
}

From source file:org.kuali.ole.select.document.service.impl.OleInvoiceServiceImpl.java

/**
 * This method is for caluclate the total amount without select proprate by Quantity,doller and manual
 *
 * @see org.kuali.ole.select.document.service.OleInvoiceService#calculateWithoutProrates(org.kuali.ole.select.document.OleInvoiceDocument)
 *//*from   w  w w  . j  a v  a2  s . c  om*/
@Override
public void calculateWithoutProrates(OleInvoiceDocument invoiceDocument) {
    LOG.debug("Inside Calculation for with out  prorate");
    BigDecimal addChargeItem = BigDecimal.ZERO;
    List<OleInvoiceItem> items = invoiceDocument.getItems();

    for (OleInvoiceItem item : items) {
        if (item.getItemTitleId() != null && !"".equals(item.getItemTitleId())) {
            if (!item.getItemListPrice().equals(item.getExtendedPrice())) {
                item.setItemUnitPrice(item.getItemListPrice().bigDecimalValue());
                item.setExtendedPrice(item.getItemListPrice());
                item.setItemSurcharge(BigDecimal.ZERO);
            }
        }
    }

    for (OleInvoiceItem item : items) {
        if (!item.getItemType().isQuantityBasedGeneralLedgerIndicator()
                && !item.getItemTypeCode()
                        .equalsIgnoreCase(PurapConstants.ItemTypeCodes.ITEM_TYPE_PMT_TERMS_DISCOUNT_CODE)
                && item.getItemUnitPrice() != null) {
            addChargeItem = addChargeItem.add(item.getItemUnitPrice());
        }
    }
    List<BigDecimal> newUnitPriceList = new ArrayList<>();
    BigDecimal totalExtPrice = new BigDecimal(0);
    BigDecimal newUnitPrice = new BigDecimal(0);
    BigDecimal extPrice = new BigDecimal(0);
    BigDecimal unitPricePercent = new BigDecimal(0);
    BigDecimal hundred = new BigDecimal(100);
    BigDecimal one = new BigDecimal(1);
    BigDecimal totalSurCharge = new BigDecimal(0);
    BigDecimal totalItemQuantity = new BigDecimal(0);
    BigDecimal itemSurchargeCons = new BigDecimal(0);
    for (int i = 0; items.size() > i; i++) {
        OleInvoiceItem item = (OleInvoiceItem) invoiceDocument.getItem(i);
        if ((item.getItemType().isQuantityBasedGeneralLedgerIndicator())
                && !ObjectUtils.isNull(item.getItemQuantity())) {
            if (item.getItemSurcharge() == null) {
                item.setItemSurcharge(BigDecimal.ZERO);
            }
            if (invoiceDocument.getProrateBy() == null) {
                if (item.getItemDiscount() == null) {
                    item.setItemDiscount(KualiDecimal.ZERO);
                }
                if (item.getItemDiscountType() != null && item.getItemDiscountType()
                        .equalsIgnoreCase(OleSelectConstant.DISCOUNT_TYPE_PERCENTAGE)) {
                    newUnitPrice = SpringContext.getBean(OlePurapService.class).calculateDiscount(item)
                            .setScale(2, BigDecimal.ROUND_HALF_UP);
                } else {
                    newUnitPrice = SpringContext.getBean(OlePurapService.class).calculateDiscount(item)
                            .setScale(2, BigDecimal.ROUND_HALF_UP);
                }
                newUnitPriceList.add(newUnitPrice);
                extPrice = newUnitPrice.multiply(item.getItemQuantity().bigDecimalValue());
                totalExtPrice = totalExtPrice.add(extPrice);
            }
            totalSurCharge = totalSurCharge
                    .add(item.getItemQuantity().bigDecimalValue().multiply(item.getItemSurcharge()));
        }
    }
    for (int i = 0, j = 0; items.size() > i; i++) {
        OleInvoiceItem item = (OleInvoiceItem) invoiceDocument.getItem(i);
        if (item.getItemType().isQuantityBasedGeneralLedgerIndicator() && newUnitPriceList.size() > j
                && !ObjectUtils.isNull(item.getItemQuantity())) {
            if (item.getItemSurcharge() != null) {
                item.setItemUnitPrice(newUnitPriceList.get(j).add(item.getItemSurcharge()));
            }
            j++;
        }
    }
    LOG.debug("Leaving Calculation for with out  prorate");
}

From source file:org.broadleafcommerce.core.pricing.service.fulfillment.provider.BandedFulfillmentPricingProvider.java

@Override
public FulfillmentEstimationResponse estimateCostForFulfillmentGroup(FulfillmentGroup fulfillmentGroup,
        Set<FulfillmentOption> options) throws FulfillmentPriceException {

    //Set up the response object
    FulfillmentEstimationResponse res = new FulfillmentEstimationResponse();
    HashMap<FulfillmentOption, Money> shippingPrices = new HashMap<FulfillmentOption, Money>();
    res.setFulfillmentOptionPrices(shippingPrices);

    for (FulfillmentOption option : options) {
        if (canCalculateCostForFulfillmentGroup(fulfillmentGroup, option)) {

            List<? extends FulfillmentBand> bands = null;
            if (option instanceof BandedPriceFulfillmentOption) {
                bands = ((BandedPriceFulfillmentOption) option).getBands();
            } else if (option instanceof BandedWeightFulfillmentOption) {
                bands = ((BandedWeightFulfillmentOption) option).getBands();
            }//from w  w  w  . j ava 2  s. co m

            if (bands == null || bands.isEmpty()) {
                //Something is misconfigured. There are no bands associated with this fulfillment option
                throw new IllegalStateException(
                        "There were no Fulfillment Price Bands configured for a BandedPriceFulfillmentOption with ID: "
                                + option.getId());
            }

            //Calculate the amount that the band will be applied to
            BigDecimal retailTotal = BigDecimal.ZERO;
            BigDecimal flatTotal = BigDecimal.ZERO;

            BigDecimal weightTotal = BigDecimal.ZERO;
            boolean foundCandidateForBand = false;
            for (FulfillmentGroupItem fulfillmentGroupItem : fulfillmentGroup.getFulfillmentGroupItems()) {

                //If this item has a Sku associated with it which also has a flat rate for this fulfillment option, don't add it to the price
                //or weight total but instead tack it onto the final rate
                boolean addToTotal = true;
                Sku sku = null;
                if (fulfillmentGroupItem.getOrderItem() instanceof DiscreteOrderItem) {
                    sku = ((DiscreteOrderItem) fulfillmentGroupItem.getOrderItem()).getSku();
                } else if (fulfillmentGroupItem.getOrderItem() instanceof BundleOrderItem) {
                    sku = ((BundleOrderItem) fulfillmentGroupItem.getOrderItem()).getSku();
                }

                if (sku != null && option.getUseFlatRates()) {
                    BigDecimal rate = sku.getFulfillmentFlatRates().get(option);
                    if (rate != null) {
                        addToTotal = false;
                        flatTotal = flatTotal.add(rate);
                    }
                }

                if (addToTotal) {
                    foundCandidateForBand = true;
                    BigDecimal price = (fulfillmentGroupItem.getTotalItemAmount() != null)
                            ? fulfillmentGroupItem.getTotalItemAmount().getAmount()
                            : null;
                    if (price == null) {
                        price = fulfillmentGroupItem.getOrderItem().getAveragePrice().getAmount()
                                .multiply(BigDecimal.valueOf(fulfillmentGroupItem.getQuantity()));
                    }
                    retailTotal = retailTotal.add(price);

                    if (sku != null && sku.getWeight() != null && sku.getWeight().getWeight() != null) {
                        BigDecimal convertedWeight = convertWeight(sku.getWeight().getWeight(),
                                sku.getWeight().getWeightUnitOfMeasure())
                                        .multiply(BigDecimal.valueOf(fulfillmentGroupItem.getQuantity()));
                        weightTotal = weightTotal.add(convertedWeight);
                    }
                }
            }

            //Used to keep track of the lowest price when there is are bands that have the same
            //minimum amount
            BigDecimal lowestBandFulfillmentPrice = null;
            //Used to keep track of the amount for the lowest band fulfillment price. Used to compare
            //if 2 bands are configured for the same minimum amount
            BigDecimal lowestBandFulfillmentPriceMinimumAmount = BigDecimal.ZERO;

            if (foundCandidateForBand) {
                for (FulfillmentBand band : bands) {

                    BigDecimal bandMinimumAmount = BigDecimal.ZERO;
                    boolean foundMatch = false;
                    if (band instanceof FulfillmentPriceBand) {
                        bandMinimumAmount = ((FulfillmentPriceBand) band).getRetailPriceMinimumAmount();
                        foundMatch = retailTotal.compareTo(bandMinimumAmount) >= 0;
                    } else if (band instanceof FulfillmentWeightBand) {
                        bandMinimumAmount = ((FulfillmentWeightBand) band).getMinimumWeight();
                        foundMatch = weightTotal.compareTo(bandMinimumAmount) >= 0;
                    }

                    if (foundMatch) {
                        //So far, we've found a potential match
                        //Now, determine if this is a percentage or actual amount
                        FulfillmentBandResultAmountType resultAmountType = band.getResultAmountType();
                        BigDecimal bandFulfillmentPrice = null;
                        if (FulfillmentBandResultAmountType.RATE.equals(resultAmountType)) {
                            bandFulfillmentPrice = band.getResultAmount();
                        } else if (FulfillmentBandResultAmountType.PERCENTAGE.equals(resultAmountType)) {
                            //Since this is a percentage, we calculate the result amount based on retailTotal and the band percentage
                            bandFulfillmentPrice = retailTotal.multiply(band.getResultAmount());
                        } else {
                            LOG.warn("Unknown FulfillmentBandResultAmountType: " + resultAmountType.getType()
                                    + " Should be RATE or PERCENTAGE. Ignoring.");
                        }

                        if (bandFulfillmentPrice != null) {

                            //haven't initialized the lowest price yet so just take on this one
                            if (lowestBandFulfillmentPrice == null) {
                                lowestBandFulfillmentPrice = bandFulfillmentPrice;
                                lowestBandFulfillmentPriceMinimumAmount = bandMinimumAmount;
                            }

                            //If there is a duplicate price band (meaning, 2 price bands are configured with the same miniumum retail price)
                            //then the lowest fulfillment amount should only be updated if the result of the current band being looked at
                            //is cheaper
                            if (lowestBandFulfillmentPriceMinimumAmount.compareTo(bandMinimumAmount) == 0) {
                                if (bandFulfillmentPrice.compareTo(lowestBandFulfillmentPrice) <= 0) {
                                    lowestBandFulfillmentPrice = bandFulfillmentPrice;
                                    lowestBandFulfillmentPriceMinimumAmount = bandMinimumAmount;
                                }
                            } else if (bandMinimumAmount
                                    .compareTo(lowestBandFulfillmentPriceMinimumAmount) > 0) {
                                lowestBandFulfillmentPrice = bandFulfillmentPrice;
                                lowestBandFulfillmentPriceMinimumAmount = bandMinimumAmount;
                            }

                        } else {
                            throw new IllegalStateException("Bands must have a non-null fulfillment price");
                        }
                    }
                }
            }

            //If I didn't find a valid band, initialize the fulfillment price to zero
            if (lowestBandFulfillmentPrice == null) {
                lowestBandFulfillmentPrice = BigDecimal.ZERO;
            }
            //add the flat rate amount calculated on the Sku
            lowestBandFulfillmentPrice = lowestBandFulfillmentPrice.add(flatTotal);

            shippingPrices.put(option, BroadleafCurrencyUtils.getMoney(lowestBandFulfillmentPrice,
                    fulfillmentGroup.getOrder().getCurrency()));
        }
    }

    return res;
}

From source file:com.konakart.bl.modules.payment.cyberpac.Cyberpac.java

/**
 * Return a payment details object for Cyberpac
 * // w  w  w.j  a  va2 s  .  c o m
 * @param order
 * @param info
 * @return Returns information in a PaymentDetails object
 * @throws Exception
 */
public PaymentDetails getPaymentDetails(Order order, PaymentInfo info) throws Exception {
    StaticData sd = staticDataHM.get(getStoreId());
    /*
     * The CyberpacZone zone, if greater than zero, should reference a GeoZone. If the
     * DeliveryAddress of the order isn't within that GeoZone, then we throw an exception
     */
    if (sd.getZone() > 0) {
        checkZone(info, sd.getZone());
    }

    // Get the scale for currency calculations
    int scale = new Integer(order.getCurrency().getDecimalPlaces()).intValue();

    // Get the resource bundle
    ResourceBundle rb = getResourceBundle(mutex, bundleName, resourceBundleMap, info.getLocale());
    if (rb == null) {
        throw new KKException(
                "A resource file cannot be found for the country " + info.getLocale().getCountry());
    }

    PaymentDetails pDetails = new PaymentDetails();
    pDetails.setCode(code);
    pDetails.setSortOrder(sd.getSortOrder());
    pDetails.setPaymentType(PaymentDetails.BROWSER_PAYMENT_GATEWAY);
    pDetails.setDescription(rb.getString(MODULE_PAYMENT_CYBERPAC_TEXT_DESCRIPTION));
    pDetails.setTitle(rb.getString(MODULE_PAYMENT_CYBERPAC_TEXT_TITLE));

    // Return now if the full payment details aren't required. This happens when the manager
    // just wants a list of payment gateways to display in the UI.
    if (info.isReturnDetails() == false) {
        return pDetails;
    }

    pDetails.setPostOrGet("post");
    pDetails.setRequestUrl(sd.getRequestUrl());

    List<NameValue> parmList = new ArrayList<NameValue>();

    /*
     * Parameters posted to gateway
     */

    // Total
    BigDecimal total = null;
    for (int i = 0; i < order.getOrderTotals().length; i++) {
        OrderTotal ot = (OrderTotal) order.getOrderTotals()[i];
        if (ot.getClassName().equals(OrderTotalMgr.ot_total)) {
            total = ot.getValue().setScale(scale, BigDecimal.ROUND_HALF_UP);
        }
    }
    if (total == null) {
        throw new KKException("An Order Total was not found in the order id = " + order.getId());
    }
    parmList.add(new NameValue("Ds_Merchant_Amount", total.toString()));

    // Currency
    String currCode = null;
    if (order.getCurrency().getCode().equalsIgnoreCase("EUR")) {
        currCode = "978";
    } else if (order.getCurrency().getCode().equalsIgnoreCase("USD")) {
        currCode = "840";
    } else if (order.getCurrency().getCode().equalsIgnoreCase("GBP")) {
        currCode = "826";
    } else if (order.getCurrency().getCode().equalsIgnoreCase("JPY")) {
        currCode = "392";
    } else {
        throw new KKException("The currency with code = " + order.getCurrency().getCode()
                + " is not supported by the Cyberpac payment gateway.");
    }
    String ds_Merchant_Currency = currCode;
    parmList.add(new NameValue("Ds_Merchant_Currency", ds_Merchant_Currency));

    // Various
    String ds_Merchant_Order = Integer.toString(order.getId());
    parmList.add(new NameValue("Ds_Merchant_Order", ds_Merchant_Order));
    parmList.add(new NameValue("Ds_Merchant_ProductDescription",
            rb.getString(MODULE_PAYMENT_CYBERPAC_CUSTOMER_MSG) + " " + order.getId()));
    parmList.add(new NameValue("Ds_Merchant_Cardholder", order.getBillingName()));
    String ds_Merchant_MerchantCode = sd.getMerchantCode();
    parmList.add(new NameValue("Ds_Merchant_MerchantCode", ds_Merchant_MerchantCode));
    parmList.add(new NameValue("Ds_Merchant_MerchantURL", sd.getCallbackUrl()));
    if (sd.getRedirectKOUrl() != null && sd.getRedirectKOUrl().length() > 0) {
        parmList.add(new NameValue("Ds_Merchant_UrlKO", sd.getRedirectKOUrl()));
    }
    if (sd.getRedirectOKUrl() != null && sd.getRedirectOKUrl().length() > 0) {
        parmList.add(new NameValue("Ds_Merchant_UrlOK", sd.getRedirectOKUrl()));
    }

    String lang = "001"; // Default Spanish Castellano
    String langCode = order.getLocale().substring(0, 2);
    if (order.getLocale().equalsIgnoreCase("ca_ES")) {
        lang = "003";
    } else if (langCode.equalsIgnoreCase("en")) {
        lang = "002";
    } else if (langCode.equalsIgnoreCase("fr")) {
        lang = "004";
    } else if (langCode.equalsIgnoreCase("de")) {
        lang = "005";
    } else if (langCode.equalsIgnoreCase("it")) {
        lang = "007";
    } else if (langCode.equalsIgnoreCase("pt")) {
        lang = "009";
    } else if (order.getLocale().equalsIgnoreCase("eu_ES")) {
        lang = "013";
    } else if (langCode.equalsIgnoreCase("ru")) {
        lang = "014";
    }
    parmList.add(new NameValue("Ds_Merchant_ConsumerLanguage", lang));

    parmList.add(new NameValue("Ds_Merchant_Terminal", sd.getTerminalNumber()));

    if (sd.getTransactionType() != null && sd.getTransactionType().length() > 0) {
        parmList.add(new NameValue("Ds_Merchant_TransactionType", sd.getTransactionType()));
    } else {
        parmList.add(new NameValue("Ds_Merchant_TransactionType", "2"));
    }

    // Data passed to us in callback. Need to create a session
    SSOTokenIf ssoToken = new SSOToken();
    String sessionId = getEng().login(sd.getCallbackUsername(), sd.getCallbackPassword());
    if (sessionId == null) {
        throw new KKException(
                "Unable to log into the engine using the Cyberpac Callback Username and Password");
    }
    ssoToken.setSessionId(sessionId);
    ssoToken.setCustom1(String.valueOf(order.getId()));
    // Save the SSOToken with a valid sessionId and the order id in custom1
    String uuid = getEng().saveSSOToken(ssoToken);
    parmList.add(new NameValue("Ds_Merchant_MerchantData", uuid));

    // Sign the data
    // Digest=SHA-1(Ds_Merchant_Amount + Ds_Merchant_Order +Ds_Merchant_MerchantCode
    // + DS_Merchant_Currency + SECRET CODE)
    String ds_Merchant_Amount = (total.multiply(new BigDecimal(100))).toString();
    String stringToSign = ds_Merchant_Amount + ds_Merchant_Order + ds_Merchant_MerchantCode
            + ds_Merchant_Currency + sd.getSecretSigningCode();
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] digest = md.digest(stringToSign.getBytes("UTF8"));
    String hexEncodedDigest = (Hex.encodeHex(digest)).toString();
    parmList.add(new NameValue("Ds_Merchant_MerchantSignature", hexEncodedDigest));
    if (log.isDebugEnabled()) {
        StringBuffer str = new StringBuffer();
        str.append("Parameters to sign:").append("\n");
        str.append("Ds_Merchant_Amount        = ").append(ds_Merchant_Amount).append("\n");
        str.append("Ds_Merchant_Order         = ").append(ds_Merchant_Order).append("\n");
        str.append("Ds_Merchant_MerchantCode  = ").append(ds_Merchant_MerchantCode).append("\n");
        str.append("Ds_Merchant_Currency      = ").append(ds_Merchant_Currency).append("\n");
        str.append("Secret Code               = ").append(sd.getSecretSigningCode()).append("\n");
        str.append("String to sign            = ").append(stringToSign).append("\n");
        str.append("SHA-1 result              = ").append(hexEncodedDigest).append("\n");
        log.debug(str);
    }

    // Put the parameters into an array
    NameValue[] nvArray = new NameValue[parmList.size()];
    parmList.toArray(nvArray);
    pDetails.setParameters(nvArray);

    if (log.isDebugEnabled()) {
        log.debug(pDetails.toString());
    }

    return pDetails;
}

From source file:com.selfsoft.business.service.impl.TbBusinessBalanceServiceImpl.java

private Double calcFavourAmount(Double itemTotal, Double favourRate) {

    BigDecimal d = new BigDecimal("0.00");

    if (null != itemTotal && null != favourRate && !favourRate.equals(1.00D)) {

        BigDecimal d_itemTotal = new BigDecimal(String.valueOf(itemTotal));

        BigDecimal d_favourRate = new BigDecimal(String.valueOf(favourRate));

        d = d_itemTotal.multiply(d_favourRate)
                .divide(new BigDecimal("1.00").subtract(d_favourRate), 2, BigDecimal.ROUND_HALF_UP)
                .setScale(2, BigDecimal.ROUND_HALF_UP);
    }//w  ww . j a v  a2s  . c om

    return d.doubleValue();
}

From source file:org.kuali.ole.select.document.service.impl.OleInvoiceServiceImpl.java

/**
 * @see org.kuali.ole.select.document.service.OleInvoiceService#calculateProrateItemSurcharge(org.kuali.ole.select.document.OleInvoiceDocument)
 */// w ww .  ja va 2 s. co  m
@Override
public void calculateProrateItemSurcharge(OleInvoiceDocument invoiceDocument) {
    LOG.debug("Inside Calculation for ProrateItemSurcharge");
    //  KualiDecimal addChargeItem = invoiceDocument.getGrandPreTaxTotalExcludingDiscount().subtract(invoiceDocument.getLineItemPreTaxTotal());
    BigDecimal addChargeItem = BigDecimal.ZERO;
    List<OleInvoiceItem> item = invoiceDocument.getItems();
    for (OleInvoiceItem items : item) {
        if (items.getItemType().isAdditionalChargeIndicator() && items.getExtendedPrice() != null) {
            addChargeItem = addChargeItem.add(items.getExtendedPrice().bigDecimalValue());
        }
    }
    List<PurApItem> items = new ArrayList<>();
    /*List<OlePurchaseOrderDocument> olePurchaseOrderDocuments = invoiceDocument.getPurchaseOrderDocuments();
    for (OlePurchaseOrderDocument olePurchaseOrderDocument : olePurchaseOrderDocuments) {
    for (OlePurchaseOrderItem purItem : (List<OlePurchaseOrderItem>) olePurchaseOrderDocument.getItems()) {
        purItem.setItemListPrice(new KualiDecimal(purItem.getInvoiceItemListPrice()));
        if (purItem.isItemForInvoice() && purItem.getItemListPrice().compareTo(KualiDecimal.ZERO) >= 0) {
            items.add(purItem);
        } else {
            purItem.setItemSurcharge(BigDecimal.ZERO);
        }
        if (purItem.getItemListPrice().compareTo(KualiDecimal.ZERO) < 0) {
            purItem.setItemUnitPrice(SpringContext.getBean(OlePurapService.class).calculateDiscount(purItem));
        }
    }
            
    }
    if (items.size() == 0) {*/
    for (OleInvoiceItem invoiceItem : (List<OleInvoiceItem>) invoiceDocument.getItems()) {
        /* if(invoiceItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && invoiceItem.getRelatedViews() != null) {
            invoiceItem.setRelatedViews(null);
        }*/
        items.add(invoiceItem);
    }
    /* }
     else {
    for (OleInvoiceItem invoiceItem : (List<OleInvoiceItem>) invoiceDocument.getItems()) {
        if (!(invoiceItem.getItemType().isQuantityBasedGeneralLedgerIndicator())) {
            items.add(invoiceItem);
        }
    }
     }*/
    List<BigDecimal> newUnitPriceList = new ArrayList<>();
    BigDecimal totalExtPrice = new BigDecimal(0);
    BigDecimal newUnitPrice = new BigDecimal(0);
    BigDecimal extPrice = new BigDecimal(0);
    BigDecimal unitPricePercent = new BigDecimal(0);
    BigDecimal hundred = new BigDecimal(100);
    BigDecimal one = new BigDecimal(1);
    BigDecimal totalSurCharge = new BigDecimal(0);
    BigDecimal totalItemQuantity = new BigDecimal(0);
    BigDecimal itemSurchargeCons = new BigDecimal(0);
    for (PurApItem purItem : items) {
        if (purItem instanceof OlePurchaseOrderItem) {
            OlePurchaseOrderItem poItem = (OlePurchaseOrderItem) purItem;
            //  purItem.setItemListPrice(new KualiDecimal(purItem.getInvoiceItemListPrice()));
            if ((poItem.getItemType().isQuantityBasedGeneralLedgerIndicator())
                    && !ObjectUtils.isNull(poItem.getNoOfCopiesInvoiced())
                    && poItem.getItemListPrice().compareTo(KualiDecimal.ZERO) >= 0) {
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
                    totalItemQuantity = totalItemQuantity.add(poItem.getNoOfCopiesInvoiced().bigDecimalValue());
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_DOLLAR)
                        || invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)
                        || invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
                    if (poItem.getItemDiscount() == null) {
                        poItem.setItemDiscount(KualiDecimal.ZERO);
                    }
                    if (poItem.getItemDiscountType() != null && poItem.getItemDiscountType()
                            .equalsIgnoreCase(OleSelectConstant.DISCOUNT_TYPE_PERCENTAGE)) {
                        newUnitPrice = (hundred.subtract(poItem.getItemDiscount().bigDecimalValue()))
                                .divide(hundred).multiply(poItem.getItemListPrice().bigDecimalValue());
                    } else {
                        newUnitPrice = poItem.getItemListPrice().bigDecimalValue()
                                .subtract(poItem.getItemDiscount().bigDecimalValue());
                    }
                    newUnitPriceList.add(newUnitPrice);
                    extPrice = newUnitPrice.multiply(poItem.getNoOfCopiesInvoiced().bigDecimalValue());
                    totalExtPrice = totalExtPrice.add(extPrice);
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)) {
                    if (poItem.getItemSurcharge() == null) {
                        poItem.setItemSurcharge(BigDecimal.ZERO);
                    }
                    totalSurCharge = totalSurCharge.add(poItem.getNoOfCopiesInvoiced().bigDecimalValue()
                            .multiply(poItem.getItemSurcharge()));
                }
            }
        }

        else if (purItem instanceof OleInvoiceItem) {
            OleInvoiceItem invItem = (OleInvoiceItem) purItem;
            if ((invItem.getItemType().isQuantityBasedGeneralLedgerIndicator())
                    && !ObjectUtils.isNull(invItem.getItemQuantity())
                    && invItem.getItemListPrice().compareTo(KualiDecimal.ZERO) >= 0) {
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
                    totalItemQuantity = totalItemQuantity.add(invItem.getItemQuantity().bigDecimalValue());
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_DOLLAR)
                        || invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)
                        || invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
                    if (invItem.getItemDiscount() == null) {
                        invItem.setItemDiscount(KualiDecimal.ZERO);
                    }
                    if (invItem.getItemDiscountType() != null && invItem.getItemDiscountType()
                            .equalsIgnoreCase(OleSelectConstant.DISCOUNT_TYPE_PERCENTAGE)) {
                        newUnitPrice = (hundred.subtract(invItem.getItemDiscount().bigDecimalValue()))
                                .divide(hundred).multiply(invItem.getItemListPrice().bigDecimalValue());
                    } else {
                        newUnitPrice = invItem.getItemListPrice().bigDecimalValue()
                                .subtract(invItem.getItemDiscount().bigDecimalValue());
                    }
                    newUnitPriceList.add(newUnitPrice);
                    extPrice = newUnitPrice.multiply(invItem.getItemQuantity().bigDecimalValue());
                    totalExtPrice = totalExtPrice.add(extPrice);
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)) {
                    if (invItem.getItemSurcharge() == null) {
                        invItem.setItemSurcharge(BigDecimal.ZERO);
                    }
                    totalSurCharge = totalSurCharge.add(
                            invItem.getItemQuantity().bigDecimalValue().multiply(invItem.getItemSurcharge()));
                }
            }
        }
    }

    if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
        if (totalItemQuantity.compareTo(BigDecimal.ZERO) != 0) {
            itemSurchargeCons = one.divide(totalItemQuantity, 8, RoundingMode.HALF_UP);
        }
    }
    for (int i = 0, j = 0; items.size() > i; i++) {
        PurApItem purItem = items.get(i);
        if (purItem instanceof OlePurchaseOrderItem) {
            OlePurchaseOrderItem poItem = (OlePurchaseOrderItem) purItem;

            if (poItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && newUnitPriceList.size() > j
                    && !ObjectUtils.isNull(poItem.getNoOfCopiesInvoiced())) {
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_DOLLAR)) {
                    if (totalExtPrice.compareTo(BigDecimal.ZERO) != 0) {
                        unitPricePercent = newUnitPriceList.get(j).divide(totalExtPrice, 8,
                                RoundingMode.HALF_UP);
                    }
                    poItem.setItemSurcharge(
                            unitPricePercent.multiply(addChargeItem).setScale(4, RoundingMode.HALF_UP));
                    poItem.setItemUnitPrice(newUnitPriceList.get(j).add(poItem.getItemSurcharge()));
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
                    poItem.setItemSurcharge(
                            itemSurchargeCons.multiply(addChargeItem).setScale(4, RoundingMode.HALF_UP));
                    poItem.setItemUnitPrice(newUnitPriceList.get(j).add(poItem.getItemSurcharge()));
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)
                        && poItem.getItemSurcharge() != null) {
                    poItem.setItemUnitPrice(newUnitPriceList.get(j).add(poItem.getItemSurcharge()));
                }
                j++;
            }
        } else if (purItem instanceof OleInvoiceItem) {
            OleInvoiceItem invItem = (OleInvoiceItem) purItem;
            if (invItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && newUnitPriceList.size() > j
                    && !ObjectUtils.isNull(invItem.getItemQuantity())) {
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_DOLLAR)) {
                    if (totalExtPrice.compareTo(BigDecimal.ZERO) != 0) {
                        unitPricePercent = newUnitPriceList.get(j).divide(totalExtPrice, 8,
                                RoundingMode.HALF_UP);
                    }
                    invItem.setItemSurcharge(
                            unitPricePercent.multiply(addChargeItem).setScale(4, RoundingMode.HALF_UP));
                    invItem.setItemUnitPrice(newUnitPriceList.get(j).add(invItem.getItemSurcharge()));
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.PRORATE_BY_QTY)) {
                    invItem.setItemSurcharge(
                            itemSurchargeCons.multiply(addChargeItem).setScale(4, RoundingMode.HALF_UP));
                    invItem.setItemUnitPrice(newUnitPriceList.get(j).add(invItem.getItemSurcharge()));
                }
                if (invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)
                        && invItem.getItemSurcharge() != null) {
                    invItem.setItemUnitPrice(newUnitPriceList.get(j).add(invItem.getItemSurcharge()));
                }
                j++;
            }

        }
    }
    if (invoiceDocument.getProrateBy().equals(OLEConstants.MANUAL_PRORATE)) {
        if (totalSurCharge.compareTo(addChargeItem) != 0) {
            GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY,
                    OLEKeyConstants.ERROR_PAYMENT_REQUEST_TOTAL_MISMATCH);
        }
    }
    LOG.debug("Leaving Calculation for ProrateItemSurcharge");
}

From source file:org.egov.ptis.domain.service.property.PropertyService.java

/**
 * Called locally to Adjust EgDemandDetails for Tax Exempted property
 *
 * @param ptDemandOld/*from  w  ww  . jav a2 s .c o m*/
 * @param newEgDemandDetails
 * @return newEgDemandDetails
 */
private Set<EgDemandDetails> adjustmentsForTaxExempted(final Set<EgDemandDetails> oldEgDemandDetails,
        final Set<EgDemandDetails> newEgDemandDetails, final Installment inst) {
    LOGGER.debug("Entered into adjustmentsForTaxExempted, oldEgDemandDetails: " + oldEgDemandDetails
            + ", newEgDemandDetails: " + newEgDemandDetails + ", inst:" + inst);
    BigDecimal totalCollAdjstmntAmnt = BigDecimal.ZERO;

    for (final EgDemandDetails egDmndDtls : oldEgDemandDetails)
        if (egDmndDtls.getEgDemandReason().getEgInstallmentMaster().equals(inst)) {
            final EgDemandReasonMaster egDmndRsnMstr = egDmndDtls.getEgDemandReason().getEgDemandReasonMaster();
            if (!egDmndRsnMstr.getCode().equalsIgnoreCase(DEMANDRSN_CODE_LIBRARY_CESS)
                    && !egDmndRsnMstr.getCode().equalsIgnoreCase(DEMANDRSN_CODE_EDUCATIONAL_TAX)
                    && !egDmndRsnMstr.getCode().equalsIgnoreCase(DEMANDRSN_CODE_UNAUTHORIZED_PENALTY))
                totalCollAdjstmntAmnt = totalCollAdjstmntAmnt.add(egDmndDtls.getAmtCollected());
        }

    final List<EgDemandDetails> newEgDmndDetails = new ArrayList<>(newEgDemandDetails);

    for (final EgDemandDetails egDmndDtls : newEgDemandDetails) {

        final EgDemandReasonMaster egDmndRsnMstr = egDmndDtls.getEgDemandReason().getEgDemandReasonMaster();

        if (egDmndRsnMstr.getCode().equalsIgnoreCase(DEMANDRSN_CODE_EDUCATIONAL_TAX))
            egDmndDtls.setAmtCollected(totalCollAdjstmntAmnt.multiply(new BigDecimal("0.50")));
        else if (egDmndRsnMstr.getCode().equalsIgnoreCase(DEMANDRSN_CODE_LIBRARY_CESS))
            egDmndDtls.setAmtCollected(totalCollAdjstmntAmnt.multiply(new BigDecimal("0.25")));
        else if (egDmndRsnMstr.getCode().equalsIgnoreCase(DEMANDRSN_CODE_UNAUTHORIZED_PENALTY))
            egDmndDtls.setAmtCollected(totalCollAdjstmntAmnt.multiply(new BigDecimal("0.25")));
    }
    LOGGER.debug("newEgDmndDetails: " + newEgDmndDetails + "\nExiting from adjustmentsForTaxExempted");
    return new HashSet<>(newEgDmndDetails);
}

From source file:com.lp.server.auftrag.ejbfac.AuftragFacBean.java

/**
 * Hier wird der Auftragsnettowert fuer eine Hibernate Liste von offenen
 * Auftraegen bestimmt (Status Offen oder Teilerledigt). <br>
 * Dabei werden alle Auftragswerte in Mandantenwaehrung beruecksichtigt.
 * //  w w  w  .jav  a 2s  .  co  m
 * @param listFLRAuftragFuerUebersichtI
 *            Liste von FLRAuftragFuerUebersicht Objekten
 * @param sessionI
 *            die aktive Hibernate Session
 * @param theClientDto
 *            der aktuelle Benutzer
 * @return BigDecimal der offene Auftragsnettowert
 * @throws Throwable
 *             Ausnahme
 */
private BigDecimal berechneAuftragsnettowertOffen(List<?> listFLRAuftragFuerUebersichtI, Session sessionI,
        TheClientDto theClientDto) throws Throwable {
    BigDecimal nSummeAuftragsnettowert = new BigDecimal(0);

    if (listFLRAuftragFuerUebersichtI != null) {
        Iterator<?> it = listFLRAuftragFuerUebersichtI.iterator();

        while (it.hasNext()) {
            BigDecimal nBeitragDiesesAuftrags = new BigDecimal(0);

            FLRAuftragFuerUebersicht flrauftrag = (FLRAuftragFuerUebersicht) it.next();

            // wir befinden uns innerhalb einer Hibernate Session
            Criteria critAuftragposition = sessionI.createCriteria(FLRAuftragpositionFuerUebersicht.class);

            critAuftragposition.add(
                    Restrictions.eq(AuftragpositionFac.FLR_AUFTRAGPOSITION_AUFTRAG_I_ID, flrauftrag.getI_id()));
            critAuftragposition
                    .add(Restrictions.isNotNull(AuftragpositionFac.FLR_AUFTRAGPOSITION_N_OFFENEMENGE));
            critAuftragposition.add(
                    Restrictions.gt(AuftragpositionFac.FLR_AUFTRAGPOSITION_N_OFFENEMENGE, new BigDecimal(0)));

            List<?> listPositionen = critAuftragposition.list();
            Iterator<?> it2 = listPositionen.iterator();

            while (it2.hasNext()) {
                FLRAuftragpositionFuerUebersicht flrauftragposition = (FLRAuftragpositionFuerUebersicht) it2
                        .next();

                BigDecimal bdBeitragDieserPosition = flrauftragposition
                        .getN_nettogesamtpreisplusversteckteraufschlagminusrabatte()
                        .multiply(flrauftragposition.getN_offenemenge());

                nBeitragDiesesAuftrags = nBeitragDiesesAuftrags.add(bdBeitragDieserPosition);
            }

            // Umrechnen des Beitrags in Mandantenwaehrung
            Double ddWechselkursReziprok = flrauftrag.getF_wechselkursmandantwaehrungzuauftragswaehrung();

            if (ddWechselkursReziprok != null && ddWechselkursReziprok.doubleValue() != 1) {
                ddWechselkursReziprok = new Double(1 / ddWechselkursReziprok.doubleValue());

                nBeitragDiesesAuftrags = nBeitragDiesesAuftrags
                        .multiply(new BigDecimal(ddWechselkursReziprok.doubleValue()));
            }

            nBeitragDiesesAuftrags = Helper.rundeKaufmaennisch(nBeitragDiesesAuftrags, 4);
            checkNumberFormat(nBeitragDiesesAuftrags);

            nSummeAuftragsnettowert = nSummeAuftragsnettowert.add(nBeitragDiesesAuftrags);
        }
    }

    return nSummeAuftragsnettowert;
}

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

public static Map<String, Object> createInvoiceForOrder(DispatchContext dctx, Map<String, Object> context) {
    Delegator delegator = dctx.getDelegator();
    LocalDispatcher dispatcher = dctx.getDispatcher();
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    Locale locale = (Locale) context.get("locale");

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

    String orderId = (String) context.get("orderId");
    List<GenericValue> billItems = UtilGenerics.checkList(context.get("billItems"));
    String invoiceId = (String) context.get("invoiceId");

    if (UtilValidate.isEmpty(billItems)) {
        Debug.logVerbose("No order items to invoice; not creating invoice; returning success", module);
        return ServiceUtil
                .returnSuccess(UtilProperties.getMessage(resource, "AccountingNoOrderItemsToInvoice", locale));
    }

    try {
        GenericValue orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId)
                .queryOne();
        if (orderHeader == null) {
            return ServiceUtil
                    .returnError(UtilProperties.getMessage(resource, "AccountingNoOrderHeader", locale));
        }

        // figure out the invoice type
        String invoiceType = null;

        String orderType = orderHeader.getString("orderTypeId");
        if (orderType.equals("SALES_ORDER")) {
            invoiceType = "SALES_INVOICE";
        } else if (orderType.equals("PURCHASE_ORDER")) {
            invoiceType = "PURCHASE_INVOICE";
        }

        // Set the precision depending on the type of invoice
        int invoiceTypeDecimals = UtilNumber.getBigDecimalScale("invoice." + invoiceType + ".decimals");
        if (invoiceTypeDecimals == -1)
            invoiceTypeDecimals = DECIMALS;

        // Make an order read helper from the order
        OrderReadHelper orh = new OrderReadHelper(orderHeader);

        // get the product store
        GenericValue productStore = orh.getProductStore();

        // get the shipping adjustment mode (Y = Pro-Rate; N = First-Invoice)
        String prorateShipping = productStore != null ? productStore.getString("prorateShipping") : "Y";
        if (prorateShipping == null) {
            prorateShipping = "Y";
        }

        // get the billing parties
        String billToCustomerPartyId = orh.getBillToParty().getString("partyId");
        String billFromVendorPartyId = orh.getBillFromParty().getString("partyId");

        // get some price totals
        BigDecimal shippableAmount = orh.getShippableTotal(null);
        BigDecimal orderSubTotal = orh.getOrderItemsSubTotal();

        // these variables are for pro-rating order amounts across invoices, so they should not be rounded off for maximum accuracy
        BigDecimal invoiceShipProRateAmount = ZERO;
        BigDecimal invoiceSubTotal = ZERO;
        BigDecimal invoiceQuantity = ZERO;

        GenericValue billingAccount = orderHeader.getRelatedOne("BillingAccount", false);
        String billingAccountId = billingAccount != null ? billingAccount.getString("billingAccountId") : null;

        Timestamp invoiceDate = (Timestamp) context.get("eventDate");
        if (UtilValidate.isEmpty(invoiceDate)) {
            // TODO: ideally this should be the same time as when a shipment is sent and be passed in as a parameter
            invoiceDate = UtilDateTime.nowTimestamp();
        }
        // TODO: perhaps consider billing account net days term as well?
        Long orderTermNetDays = orh.getOrderTermNetDays();
        Timestamp dueDate = null;
        if (orderTermNetDays != null) {
            dueDate = UtilDateTime.getDayEnd(invoiceDate, orderTermNetDays);
        }

        // create the invoice record
        if (UtilValidate.isEmpty(invoiceId)) {
            Map<String, Object> createInvoiceContext = FastMap.newInstance();
            createInvoiceContext.put("partyId", billToCustomerPartyId);
            createInvoiceContext.put("partyIdFrom", billFromVendorPartyId);
            createInvoiceContext.put("billingAccountId", billingAccountId);
            createInvoiceContext.put("invoiceDate", invoiceDate);
            createInvoiceContext.put("dueDate", dueDate);
            createInvoiceContext.put("invoiceTypeId", invoiceType);
            // start with INVOICE_IN_PROCESS, in the INVOICE_READY we can't change the invoice (or shouldn't be able to...)
            createInvoiceContext.put("statusId", "INVOICE_IN_PROCESS");
            createInvoiceContext.put("currencyUomId", orderHeader.getString("currencyUom"));
            createInvoiceContext.put("userLogin", userLogin);

            // store the invoice first
            Map<String, Object> createInvoiceResult = dispatcher.runSync("createInvoice", createInvoiceContext);
            if (ServiceUtil.isError(createInvoiceResult)) {
                return ServiceUtil.returnError(
                        UtilProperties.getMessage(resource, "AccountingErrorCreatingInvoiceFromOrder", locale),
                        null, null, createInvoiceResult);
            }

            // call service, not direct entity op: delegator.create(invoice);
            invoiceId = (String) createInvoiceResult.get("invoiceId");
        }

        // order roles to invoice roles
        List<GenericValue> orderRoles = orderHeader.getRelated("OrderRole", null, null, false);
        Map<String, Object> createInvoiceRoleContext = FastMap.newInstance();
        createInvoiceRoleContext.put("invoiceId", invoiceId);
        createInvoiceRoleContext.put("userLogin", userLogin);
        for (GenericValue orderRole : orderRoles) {
            createInvoiceRoleContext.put("partyId", orderRole.getString("partyId"));
            createInvoiceRoleContext.put("roleTypeId", orderRole.getString("roleTypeId"));
            Map<String, Object> createInvoiceRoleResult = dispatcher.runSync("createInvoiceRole",
                    createInvoiceRoleContext);
            if (ServiceUtil.isError(createInvoiceRoleResult)) {
                return ServiceUtil.returnError(
                        UtilProperties.getMessage(resource, "AccountingErrorCreatingInvoiceFromOrder", locale),
                        null, null, createInvoiceRoleResult);
            }
        }

        // order terms to invoice terms.
        // TODO: it might be nice to filter OrderTerms to only copy over financial terms.
        List<GenericValue> orderTerms = orh.getOrderTerms();
        createInvoiceTerms(delegator, dispatcher, invoiceId, orderTerms, userLogin, locale);

        // billing accounts
        // List billingAccountTerms = null;
        // for billing accounts we will use related information
        if (billingAccount != null) {
            /*
             * jacopoc: billing account terms were already copied as order terms
             *          when the order was created.
            // get the billing account terms
            billingAccountTerms = billingAccount.getRelated("BillingAccountTerm", null, null, false);
                    
            // set the invoice terms as defined for the billing account
            createInvoiceTerms(delegator, dispatcher, invoiceId, billingAccountTerms, userLogin, locale);
            */
            // set the invoice bill_to_customer from the billing account
            List<GenericValue> billToRoles = billingAccount.getRelated("BillingAccountRole",
                    UtilMisc.toMap("roleTypeId", "BILL_TO_CUSTOMER"), null, false);
            for (GenericValue billToRole : billToRoles) {
                if (!(billToRole.getString("partyId").equals(billToCustomerPartyId))) {
                    createInvoiceRoleContext = UtilMisc.toMap("invoiceId", invoiceId, "partyId",
                            billToRole.get("partyId"), "roleTypeId", "BILL_TO_CUSTOMER", "userLogin",
                            userLogin);
                    Map<String, Object> createInvoiceRoleResult = dispatcher.runSync("createInvoiceRole",
                            createInvoiceRoleContext);
                    if (ServiceUtil.isError(createInvoiceRoleResult)) {
                        return ServiceUtil.returnError(
                                UtilProperties.getMessage(resource,
                                        "AccountingErrorCreatingInvoiceRoleFromOrder", locale),
                                null, null, createInvoiceRoleResult);
                    }
                }
            }

            // set the bill-to contact mech as the contact mech of the billing account
            if (UtilValidate.isNotEmpty(billingAccount.getString("contactMechId"))) {
                Map<String, Object> createBillToContactMechContext = UtilMisc.toMap("invoiceId", invoiceId,
                        "contactMechId", billingAccount.getString("contactMechId"), "contactMechPurposeTypeId",
                        "BILLING_LOCATION", "userLogin", userLogin);
                Map<String, Object> createBillToContactMechResult = dispatcher
                        .runSync("createInvoiceContactMech", createBillToContactMechContext);
                if (ServiceUtil.isError(createBillToContactMechResult)) {
                    return ServiceUtil.returnError(
                            UtilProperties.getMessage(resource,
                                    "AccountingErrorCreatingInvoiceContactMechFromOrder", locale),
                            null, null, createBillToContactMechResult);
                }
            }
        } else {
            List<GenericValue> billingLocations = orh.getBillingLocations();
            if (UtilValidate.isNotEmpty(billingLocations)) {
                for (GenericValue ocm : billingLocations) {
                    Map<String, Object> createBillToContactMechContext = UtilMisc.toMap("invoiceId", invoiceId,
                            "contactMechId", ocm.getString("contactMechId"), "contactMechPurposeTypeId",
                            "BILLING_LOCATION", "userLogin", userLogin);
                    Map<String, Object> createBillToContactMechResult = dispatcher
                            .runSync("createInvoiceContactMech", createBillToContactMechContext);
                    if (ServiceUtil.isError(createBillToContactMechResult)) {
                        return ServiceUtil.returnError(
                                UtilProperties.getMessage(resource,
                                        "AccountingErrorCreatingInvoiceContactMechFromOrder", locale),
                                null, null, createBillToContactMechResult);
                    }
                }
            } else {
                Debug.logWarning("No billing locations found for order [" + orderId
                        + "] and none were created for Invoice [" + invoiceId + "]", module);
            }
        }

        // get a list of the payment method types
        //DEJ20050705 doesn't appear to be used: List paymentPreferences = orderHeader.getRelated("OrderPaymentPreference", null, null, false);

        // create the bill-from (or pay-to) contact mech as the primary PAYMENT_LOCATION of the party from the store
        GenericValue payToAddress = null;
        if (invoiceType.equals("PURCHASE_INVOICE")) {
            // for purchase orders, the pay to address is the BILLING_LOCATION of the vendor
            GenericValue billFromVendor = orh.getPartyFromRole("BILL_FROM_VENDOR");
            if (billFromVendor != null) {
                List<GenericValue> billingContactMechs = billFromVendor.getRelatedOne("Party", false)
                        .getRelated("PartyContactMechPurpose",
                                UtilMisc.toMap("contactMechPurposeTypeId", "BILLING_LOCATION"), null, false);
                if (UtilValidate.isNotEmpty(billingContactMechs)) {
                    payToAddress = EntityUtil.getFirst(billingContactMechs);
                }
            }
        } else {
            // for sales orders, it is the payment address on file for the store
            payToAddress = PaymentWorker.getPaymentAddress(delegator, productStore.getString("payToPartyId"));
        }
        if (payToAddress != null) {
            Map<String, Object> createPayToContactMechContext = UtilMisc.toMap("invoiceId", invoiceId,
                    "contactMechId", payToAddress.getString("contactMechId"), "contactMechPurposeTypeId",
                    "PAYMENT_LOCATION", "userLogin", userLogin);
            Map<String, Object> createPayToContactMechResult = dispatcher.runSync("createInvoiceContactMech",
                    createPayToContactMechContext);
            if (ServiceUtil.isError(createPayToContactMechResult)) {
                return ServiceUtil.returnError(
                        UtilProperties.getMessage(resource,
                                "AccountingErrorCreatingInvoiceContactMechFromOrder", locale),
                        null, null, createPayToContactMechResult);
            }
        }

        // sequence for items - all OrderItems or InventoryReservations + all Adjustments
        int invoiceItemSeqNum = 1;
        String invoiceItemSeqId = UtilFormatOut.formatPaddedNumber(invoiceItemSeqNum,
                INVOICE_ITEM_SEQUENCE_ID_DIGITS);

        // create the item records
        for (GenericValue currentValue : billItems) {
            GenericValue itemIssuance = null;
            GenericValue orderItem = null;
            GenericValue shipmentReceipt = null;
            if ("ItemIssuance".equals(currentValue.getEntityName())) {
                itemIssuance = currentValue;
            } else if ("OrderItem".equals(currentValue.getEntityName())) {
                orderItem = currentValue;
            } else if ("ShipmentReceipt".equals(currentValue.getEntityName())) {
                shipmentReceipt = currentValue;
            } else {
                Debug.logError("Unexpected entity " + currentValue + " of type " + currentValue.getEntityName(),
                        module);
            }

            if (orderItem == null && itemIssuance != null) {
                orderItem = itemIssuance.getRelatedOne("OrderItem", false);
            } else if ((orderItem == null) && (shipmentReceipt != null)) {
                orderItem = shipmentReceipt.getRelatedOne("OrderItem", false);
            } else if ((orderItem == null) && (itemIssuance == null) && (shipmentReceipt == null)) {
                Debug.logError(
                        "Cannot create invoice when orderItem, itemIssuance, and shipmentReceipt are all null",
                        module);
                return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                        "AccountingIllegalValuesPassedToCreateInvoiceService", locale));
            }
            GenericValue product = null;
            if (orderItem.get("productId") != null) {
                product = orderItem.getRelatedOne("Product", false);
            }

            // get some quantities
            BigDecimal billingQuantity = null;
            if (itemIssuance != null) {
                billingQuantity = itemIssuance.getBigDecimal("quantity");
                BigDecimal cancelQty = itemIssuance.getBigDecimal("cancelQuantity");
                if (cancelQty == null) {
                    cancelQty = ZERO;
                }
                billingQuantity = billingQuantity.subtract(cancelQty).setScale(DECIMALS, ROUNDING);
            } else if (shipmentReceipt != null) {
                billingQuantity = shipmentReceipt.getBigDecimal("quantityAccepted");
            } else {
                BigDecimal orderedQuantity = OrderReadHelper.getOrderItemQuantity(orderItem);
                BigDecimal invoicedQuantity = OrderReadHelper.getOrderItemInvoicedQuantity(orderItem);
                billingQuantity = orderedQuantity.subtract(invoicedQuantity);
                if (billingQuantity.compareTo(ZERO) < 0) {
                    billingQuantity = ZERO;
                }
            }
            if (billingQuantity == null)
                billingQuantity = ZERO;

            // check if shipping applies to this item.  Shipping is calculated for sales invoices, not purchase invoices.
            boolean shippingApplies = false;
            if ((product != null) && (ProductWorker.shippingApplies(product))
                    && (invoiceType.equals("SALES_INVOICE"))) {
                shippingApplies = true;
            }

            BigDecimal billingAmount = orderItem.getBigDecimal("unitPrice").setScale(invoiceTypeDecimals,
                    ROUNDING);

            Map<String, Object> createInvoiceItemContext = FastMap.newInstance();
            createInvoiceItemContext.put("invoiceId", invoiceId);
            createInvoiceItemContext.put("invoiceItemSeqId", invoiceItemSeqId);
            createInvoiceItemContext.put("invoiceItemTypeId",
                    getInvoiceItemType(delegator, (orderItem.getString("orderItemTypeId")),
                            (product == null ? null : product.getString("productTypeId")), invoiceType,
                            "INV_FPROD_ITEM"));
            createInvoiceItemContext.put("description", orderItem.get("itemDescription"));
            createInvoiceItemContext.put("quantity", billingQuantity);
            createInvoiceItemContext.put("amount", billingAmount);
            createInvoiceItemContext.put("productId", orderItem.get("productId"));
            createInvoiceItemContext.put("productFeatureId", orderItem.get("productFeatureId"));
            createInvoiceItemContext.put("overrideGlAccountId", orderItem.get("overrideGlAccountId"));
            //createInvoiceItemContext.put("uomId", "");
            createInvoiceItemContext.put("userLogin", userLogin);

            String itemIssuanceId = null;
            if (itemIssuance != null && itemIssuance.get("inventoryItemId") != null) {
                itemIssuanceId = itemIssuance.getString("itemIssuanceId");
                createInvoiceItemContext.put("inventoryItemId", itemIssuance.get("inventoryItemId"));
            }
            // similarly, tax only for purchase invoices
            if ((product != null) && (invoiceType.equals("SALES_INVOICE"))) {
                createInvoiceItemContext.put("taxableFlag", product.get("taxable"));
            }

            Map<String, Object> createInvoiceItemResult = dispatcher.runSync("createInvoiceItem",
                    createInvoiceItemContext);
            if (ServiceUtil.isError(createInvoiceItemResult)) {
                return ServiceUtil
                        .returnError(
                                UtilProperties.getMessage(resource,
                                        "AccountingErrorCreatingInvoiceItemFromOrder", locale),
                                null, null, createInvoiceItemResult);
            }

            // this item total
            BigDecimal thisAmount = billingAmount.multiply(billingQuantity).setScale(invoiceTypeDecimals,
                    ROUNDING);

            // add to the ship amount only if it applies to this item
            if (shippingApplies) {
                invoiceShipProRateAmount = invoiceShipProRateAmount.add(thisAmount)
                        .setScale(invoiceTypeDecimals, ROUNDING);
            }

            // increment the invoice subtotal
            invoiceSubTotal = invoiceSubTotal.add(thisAmount).setScale(100, ROUNDING);

            // increment the invoice quantity
            invoiceQuantity = invoiceQuantity.add(billingQuantity).setScale(invoiceTypeDecimals, ROUNDING);

            // create the OrderItemBilling record
            Map<String, Object> createOrderItemBillingContext = FastMap.newInstance();
            createOrderItemBillingContext.put("invoiceId", invoiceId);
            createOrderItemBillingContext.put("invoiceItemSeqId", invoiceItemSeqId);
            createOrderItemBillingContext.put("orderId", orderItem.get("orderId"));
            createOrderItemBillingContext.put("orderItemSeqId", orderItem.get("orderItemSeqId"));
            createOrderItemBillingContext.put("itemIssuanceId", itemIssuanceId);
            createOrderItemBillingContext.put("quantity", billingQuantity);
            createOrderItemBillingContext.put("amount", billingAmount);
            createOrderItemBillingContext.put("userLogin", userLogin);
            if ((shipmentReceipt != null) && (shipmentReceipt.getString("receiptId") != null)) {
                createOrderItemBillingContext.put("shipmentReceiptId", shipmentReceipt.getString("receiptId"));
            }

            Map<String, Object> createOrderItemBillingResult = dispatcher.runSync("createOrderItemBilling",
                    createOrderItemBillingContext);
            if (ServiceUtil.isError(createOrderItemBillingResult)) {
                return ServiceUtil
                        .returnError(
                                UtilProperties.getMessage(resource,
                                        "AccountingErrorCreatingOrderItemBillingFromOrder", locale),
                                null, null, createOrderItemBillingResult);
            }

            if ("ItemIssuance".equals(currentValue.getEntityName())) {
                List<GenericValue> shipmentItemBillings = EntityQuery.use(delegator).from("ShipmentItemBilling")
                        .where("shipmentId", currentValue.get("shipmentId"), "shipmentItemSeqId",
                                currentValue.get("shipmentItemSeqId"))
                        .queryList();
                if (UtilValidate.isEmpty(shipmentItemBillings)) {

                    // create the ShipmentItemBilling record
                    GenericValue shipmentItemBilling = delegator.makeValue("ShipmentItemBilling",
                            UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId));
                    shipmentItemBilling.put("shipmentId", currentValue.get("shipmentId"));
                    shipmentItemBilling.put("shipmentItemSeqId", currentValue.get("shipmentItemSeqId"));
                    shipmentItemBilling.create();
                }
            }

            String parentInvoiceItemSeqId = invoiceItemSeqId;
            // increment the counter
            invoiceItemSeqNum++;
            invoiceItemSeqId = UtilFormatOut.formatPaddedNumber(invoiceItemSeqNum,
                    INVOICE_ITEM_SEQUENCE_ID_DIGITS);

            // Get the original order item from the DB, in case the quantity has been overridden
            GenericValue originalOrderItem = EntityQuery.use(delegator).from("OrderItem")
                    .where("orderId", orderId, "orderItemSeqId", orderItem.get("orderItemSeqId")).queryOne();

            // create the item adjustment as line items
            List<GenericValue> itemAdjustments = OrderReadHelper.getOrderItemAdjustmentList(orderItem,
                    orh.getAdjustments());
            for (GenericValue adj : itemAdjustments) {

                // Check against OrderAdjustmentBilling to see how much of this adjustment has already been invoiced
                BigDecimal adjAlreadyInvoicedAmount = null;
                try {
                    Map<String, Object> checkResult = dispatcher.runSync("calculateInvoicedAdjustmentTotal",
                            UtilMisc.toMap("orderAdjustment", adj));
                    adjAlreadyInvoicedAmount = (BigDecimal) checkResult.get("invoicedTotal");
                } catch (GenericServiceException e) {
                    Debug.logError(e, "Accounting trouble calling calculateInvoicedAdjustmentTotal service",
                            module);
                    return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                            "AccountingTroubleCallingCalculateInvoicedAdjustmentTotalService", locale));
                }

                // If the absolute invoiced amount >= the abs of the adjustment amount, the full amount has already been invoiced,
                //  so skip this adjustment
                if (adj.get("amount") == null) { // JLR 17/4/7 : fix a bug coming from POS in case of use of a discount (on item(s) or sale, item(s) here) and a cash amount higher than total (hence issuing change)
                    continue;
                }
                if (adjAlreadyInvoicedAmount.abs().compareTo(
                        adj.getBigDecimal("amount").setScale(invoiceTypeDecimals, ROUNDING).abs()) > 0) {
                    continue;
                }

                BigDecimal originalOrderItemQuantity = OrderReadHelper.getOrderItemQuantity(originalOrderItem);
                BigDecimal amount = ZERO;
                if (originalOrderItemQuantity.signum() != 0) {
                    if (adj.get("amount") != null) {
                        // pro-rate the amount
                        // set decimals = 100 means we don't round this intermediate value, which is very important
                        amount = adj.getBigDecimal("amount").divide(originalOrderItemQuantity, 100, ROUNDING);
                        amount = amount.multiply(billingQuantity);
                        // Tax needs to be rounded differently from other order adjustments
                        if (adj.getString("orderAdjustmentTypeId").equals("SALES_TAX")) {
                            amount = amount.setScale(TAX_DECIMALS, TAX_ROUNDING);
                        } else {
                            amount = amount.setScale(invoiceTypeDecimals, ROUNDING);
                        }
                    } else if (adj.get("sourcePercentage") != null) {
                        // pro-rate the amount
                        // set decimals = 100 means we don't round this intermediate value, which is very important
                        BigDecimal percent = adj.getBigDecimal("sourcePercentage");
                        percent = percent.divide(new BigDecimal(100), 100, ROUNDING);
                        amount = billingAmount.multiply(percent);
                        amount = amount.divide(originalOrderItemQuantity, 100, ROUNDING);
                        amount = amount.multiply(billingQuantity);
                        amount = amount.setScale(invoiceTypeDecimals, ROUNDING);
                    }
                }
                if (amount.signum() != 0) {
                    Map<String, Object> createInvoiceItemAdjContext = FastMap.newInstance();
                    createInvoiceItemAdjContext.put("invoiceId", invoiceId);
                    createInvoiceItemAdjContext.put("invoiceItemSeqId", invoiceItemSeqId);
                    createInvoiceItemAdjContext.put("invoiceItemTypeId", getInvoiceItemType(delegator,
                            adj.getString("orderAdjustmentTypeId"), null, invoiceType, "INVOICE_ITM_ADJ"));
                    createInvoiceItemAdjContext.put("quantity", BigDecimal.ONE);
                    createInvoiceItemAdjContext.put("amount", amount);
                    createInvoiceItemAdjContext.put("productId", orderItem.get("productId"));
                    createInvoiceItemAdjContext.put("productFeatureId", orderItem.get("productFeatureId"));
                    createInvoiceItemAdjContext.put("overrideGlAccountId", adj.get("overrideGlAccountId"));
                    createInvoiceItemAdjContext.put("parentInvoiceId", invoiceId);
                    createInvoiceItemAdjContext.put("parentInvoiceItemSeqId", parentInvoiceItemSeqId);
                    //createInvoiceItemAdjContext.put("uomId", "");
                    createInvoiceItemAdjContext.put("userLogin", userLogin);
                    createInvoiceItemAdjContext.put("taxAuthPartyId", adj.get("taxAuthPartyId"));
                    createInvoiceItemAdjContext.put("taxAuthGeoId", adj.get("taxAuthGeoId"));
                    createInvoiceItemAdjContext.put("taxAuthorityRateSeqId", adj.get("taxAuthorityRateSeqId"));

                    // some adjustments fill out the comments field instead
                    String description = (UtilValidate.isEmpty(adj.getString("description"))
                            ? adj.getString("comments")
                            : adj.getString("description"));
                    createInvoiceItemAdjContext.put("description", description);

                    // invoice items for sales tax are not taxable themselves
                    // TODO: This is not an ideal solution. Instead, we need to use OrderAdjustment.includeInTax when it is implemented
                    if (!(adj.getString("orderAdjustmentTypeId").equals("SALES_TAX"))) {
                        createInvoiceItemAdjContext.put("taxableFlag", product.get("taxable"));
                    }

                    // If the OrderAdjustment is associated to a ProductPromo,
                    // and the field ProductPromo.overrideOrgPartyId is set,
                    // copy the value to InvoiceItem.overrideOrgPartyId: this
                    // represent an organization override for the payToPartyId
                    if (UtilValidate.isNotEmpty(adj.getString("productPromoId"))) {
                        try {
                            GenericValue productPromo = adj.getRelatedOne("ProductPromo", false);
                            if (UtilValidate.isNotEmpty(productPromo.getString("overrideOrgPartyId"))) {
                                createInvoiceItemAdjContext.put("overrideOrgPartyId",
                                        productPromo.getString("overrideOrgPartyId"));
                            }
                        } catch (GenericEntityException e) {
                            Debug.logError(e, "Error looking up ProductPromo with id ["
                                    + adj.getString("productPromoId") + "]", module);
                        }
                    }

                    Map<String, Object> createInvoiceItemAdjResult = dispatcher.runSync("createInvoiceItem",
                            createInvoiceItemAdjContext);
                    if (ServiceUtil.isError(createInvoiceItemAdjResult)) {
                        return ServiceUtil.returnError(
                                UtilProperties.getMessage(resource,
                                        "AccountingErrorCreatingInvoiceItemFromOrder", locale),
                                null, null, createInvoiceItemAdjResult);
                    }

                    // Create the OrderAdjustmentBilling record
                    Map<String, Object> createOrderAdjustmentBillingContext = FastMap.newInstance();
                    createOrderAdjustmentBillingContext.put("orderAdjustmentId",
                            adj.getString("orderAdjustmentId"));
                    createOrderAdjustmentBillingContext.put("invoiceId", invoiceId);
                    createOrderAdjustmentBillingContext.put("invoiceItemSeqId", invoiceItemSeqId);
                    createOrderAdjustmentBillingContext.put("amount", amount);
                    createOrderAdjustmentBillingContext.put("userLogin", userLogin);

                    Map<String, Object> createOrderAdjustmentBillingResult = dispatcher
                            .runSync("createOrderAdjustmentBilling", createOrderAdjustmentBillingContext);
                    if (ServiceUtil.isError(createOrderAdjustmentBillingResult)) {
                        return ServiceUtil.returnError(
                                UtilProperties.getMessage(resource,
                                        "AccountingErrorCreatingOrderAdjustmentBillingFromOrder", locale),
                                null, null, createOrderAdjustmentBillingContext);
                    }

                    // this adjustment amount
                    BigDecimal thisAdjAmount = amount;

                    // adjustments only apply to totals when they are not tax or shipping adjustments
                    if (!"SALES_TAX".equals(adj.getString("orderAdjustmentTypeId"))
                            && !"SHIPPING_ADJUSTMENT".equals(adj.getString("orderAdjustmentTypeId"))) {
                        // increment the invoice subtotal
                        invoiceSubTotal = invoiceSubTotal.add(thisAdjAmount).setScale(100, ROUNDING);

                        // add to the ship amount only if it applies to this item
                        if (shippingApplies) {
                            invoiceShipProRateAmount = invoiceShipProRateAmount.add(thisAdjAmount)
                                    .setScale(invoiceTypeDecimals, ROUNDING);
                        }
                    }

                    // increment the counter
                    invoiceItemSeqNum++;
                    invoiceItemSeqId = UtilFormatOut.formatPaddedNumber(invoiceItemSeqNum,
                            INVOICE_ITEM_SEQUENCE_ID_DIGITS);
                }
            }
        }

        // create header adjustments as line items -- always to tax/shipping last
        Map<GenericValue, BigDecimal> shipAdjustments = FastMap.newInstance();
        Map<GenericValue, BigDecimal> taxAdjustments = FastMap.newInstance();

        List<GenericValue> headerAdjustments = orh.getOrderHeaderAdjustments();
        for (GenericValue adj : headerAdjustments) {

            // Check against OrderAdjustmentBilling to see how much of this adjustment has already been invoiced
            BigDecimal adjAlreadyInvoicedAmount = null;
            try {
                Map<String, Object> checkResult = dispatcher.runSync("calculateInvoicedAdjustmentTotal",
                        UtilMisc.toMap("orderAdjustment", adj));
                adjAlreadyInvoicedAmount = ((BigDecimal) checkResult.get("invoicedTotal"))
                        .setScale(invoiceTypeDecimals, ROUNDING);
            } catch (GenericServiceException e) {
                Debug.logError(e, "Accounting trouble calling calculateInvoicedAdjustmentTotal service",
                        module);
                return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                        "AccountingTroubleCallingCalculateInvoicedAdjustmentTotalService", locale));
            }

            // If the absolute invoiced amount >= the abs of the adjustment amount, the full amount has already been invoiced,
            //  so skip this adjustment
            if (null == adj.get("amount")) { // JLR 17/4/7 : fix a bug coming from POS in case of use of a discount (on item(s) or sale, sale here) and a cash amount higher than total (hence issuing change)
                continue;
            }
            if (adjAlreadyInvoicedAmount.abs()
                    .compareTo(adj.getBigDecimal("amount").setScale(invoiceTypeDecimals, ROUNDING).abs()) > 0) {
                continue;
            }

            if ("SHIPPING_CHARGES".equals(adj.getString("orderAdjustmentTypeId"))) {
                shipAdjustments.put(adj, adjAlreadyInvoicedAmount);
            } else if ("SALES_TAX".equals(adj.getString("orderAdjustmentTypeId"))) {
                taxAdjustments.put(adj, adjAlreadyInvoicedAmount);
            } else {
                // these will effect the shipping pro-rate (unless commented)
                // other adjustment type
                calcHeaderAdj(delegator, adj, invoiceType, invoiceId, invoiceItemSeqId, orderSubTotal,
                        invoiceSubTotal, adj.getBigDecimal("amount").setScale(invoiceTypeDecimals, ROUNDING),
                        invoiceTypeDecimals, ROUNDING, userLogin, dispatcher, locale);
                // invoiceShipProRateAmount += adjAmount;
                // do adjustments compound or are they based off subtotal? Here we will (unless commented)
                // invoiceSubTotal += adjAmount;

                // increment the counter
                invoiceItemSeqNum++;
                invoiceItemSeqId = UtilFormatOut.formatPaddedNumber(invoiceItemSeqNum,
                        INVOICE_ITEM_SEQUENCE_ID_DIGITS);
            }
        }

        // next do the shipping adjustments.  Note that we do not want to add these to the invoiceSubTotal or orderSubTotal for pro-rating tax later, as that would cause
        // numerator/denominator problems when the shipping is not pro-rated but rather charged all on the first invoice
        for (GenericValue adj : shipAdjustments.keySet()) {
            BigDecimal adjAlreadyInvoicedAmount = shipAdjustments.get(adj);

            if ("N".equalsIgnoreCase(prorateShipping)) {

                // Set the divisor and multiplier to 1 to avoid prorating
                BigDecimal divisor = BigDecimal.ONE;
                BigDecimal multiplier = BigDecimal.ONE;

                // The base amount in this case is the adjustment amount minus the total already invoiced for that adjustment, since
                //  it won't be prorated
                BigDecimal baseAmount = adj.getBigDecimal("amount").setScale(invoiceTypeDecimals, ROUNDING)
                        .subtract(adjAlreadyInvoicedAmount);
                calcHeaderAdj(delegator, adj, invoiceType, invoiceId, invoiceItemSeqId, divisor, multiplier,
                        baseAmount, invoiceTypeDecimals, ROUNDING, userLogin, dispatcher, locale);
            } else {

                // Pro-rate the shipping amount based on shippable information
                BigDecimal divisor = shippableAmount;
                BigDecimal multiplier = invoiceShipProRateAmount;

                // The base amount in this case is the adjustment amount, since we want to prorate based on the full amount
                BigDecimal baseAmount = adj.getBigDecimal("amount").setScale(invoiceTypeDecimals, ROUNDING);
                calcHeaderAdj(delegator, adj, invoiceType, invoiceId, invoiceItemSeqId, divisor, multiplier,
                        baseAmount, invoiceTypeDecimals, ROUNDING, userLogin, dispatcher, locale);
            }

            // Increment the counter
            invoiceItemSeqNum++;
            invoiceItemSeqId = UtilFormatOut.formatPaddedNumber(invoiceItemSeqNum,
                    INVOICE_ITEM_SEQUENCE_ID_DIGITS);
        }

        // last do the tax adjustments
        String prorateTaxes = productStore != null ? productStore.getString("prorateTaxes") : "Y";
        if (prorateTaxes == null) {
            prorateTaxes = "Y";
        }
        for (Map.Entry<GenericValue, BigDecimal> entry : taxAdjustments.entrySet()) {
            GenericValue adj = entry.getKey();
            BigDecimal adjAlreadyInvoicedAmount = entry.getValue();
            BigDecimal adjAmount = null;

            if ("N".equalsIgnoreCase(prorateTaxes)) {

                // Set the divisor and multiplier to 1 to avoid prorating
                BigDecimal divisor = BigDecimal.ONE;
                BigDecimal multiplier = BigDecimal.ONE;

                // The base amount in this case is the adjustment amount minus the total already invoiced for that adjustment, since
                //  it won't be prorated
                BigDecimal baseAmount = adj.getBigDecimal("amount").setScale(TAX_DECIMALS, TAX_ROUNDING)
                        .subtract(adjAlreadyInvoicedAmount);
                adjAmount = calcHeaderAdj(delegator, adj, invoiceType, invoiceId, invoiceItemSeqId, divisor,
                        multiplier, baseAmount, TAX_DECIMALS, TAX_ROUNDING, userLogin, dispatcher, locale);
            } else {

                // Pro-rate the tax amount based on shippable information
                BigDecimal divisor = orderSubTotal;
                BigDecimal multiplier = invoiceSubTotal;

                // The base amount in this case is the adjustment amount, since we want to prorate based on the full amount
                BigDecimal baseAmount = adj.getBigDecimal("amount");
                adjAmount = calcHeaderAdj(delegator, adj, invoiceType, invoiceId, invoiceItemSeqId, divisor,
                        multiplier, baseAmount, TAX_DECIMALS, TAX_ROUNDING, userLogin, dispatcher, locale);
            }
            invoiceSubTotal = invoiceSubTotal.add(adjAmount).setScale(invoiceTypeDecimals, ROUNDING);

            // Increment the counter
            invoiceItemSeqNum++;
            invoiceItemSeqId = UtilFormatOut.formatPaddedNumber(invoiceItemSeqNum,
                    INVOICE_ITEM_SEQUENCE_ID_DIGITS);
        }

        // check for previous order payments
        List<GenericValue> orderPaymentPrefs = EntityQuery.use(delegator).from("OrderPaymentPreference").where(
                EntityCondition.makeCondition("orderId", EntityOperator.EQUALS, orderId),
                EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "PAYMENT_CANCELLED"))
                .queryList();
        List<GenericValue> currentPayments = FastList.newInstance();
        for (GenericValue paymentPref : orderPaymentPrefs) {
            List<GenericValue> payments = paymentPref.getRelated("Payment", null, null, false);
            currentPayments.addAll(payments);
        }
        // apply these payments to the invoice if they have any remaining amount to apply
        for (GenericValue payment : currentPayments) {
            if ("PMNT_VOID".equals(payment.getString("statusId"))
                    || "PMNT_CANCELLED".equals(payment.getString("statusId"))) {
                continue;
            }
            BigDecimal notApplied = PaymentWorker.getPaymentNotApplied(payment);
            if (notApplied.signum() > 0) {
                Map<String, Object> appl = FastMap.newInstance();
                appl.put("paymentId", payment.get("paymentId"));
                appl.put("invoiceId", invoiceId);
                appl.put("billingAccountId", billingAccountId);
                appl.put("amountApplied", notApplied);
                appl.put("userLogin", userLogin);
                Map<String, Object> createPayApplResult = dispatcher.runSync("createPaymentApplication", appl);
                if (ServiceUtil.isError(createPayApplResult)) {
                    return ServiceUtil
                            .returnError(
                                    UtilProperties.getMessage(resource,
                                            "AccountingErrorCreatingInvoiceFromOrder", locale),
                                    null, null, createPayApplResult);
                }
            }
        }

        // Should all be in place now. Depending on the ProductStore.autoApproveInvoice setting, set status to INVOICE_READY (unless it's a purchase invoice, which we set to INVOICE_IN_PROCESS)
        String autoApproveInvoice = productStore != null ? productStore.getString("autoApproveInvoice") : "Y";
        if (!"N".equals(autoApproveInvoice)) {
            String nextStatusId = "PURCHASE_INVOICE".equals(invoiceType) ? "INVOICE_IN_PROCESS"
                    : "INVOICE_READY";
            Map<String, Object> setInvoiceStatusResult = dispatcher.runSync("setInvoiceStatus",
                    UtilMisc.<String, Object>toMap("invoiceId", invoiceId, "statusId", nextStatusId,
                            "userLogin", userLogin));
            if (ServiceUtil.isError(setInvoiceStatusResult)) {
                return ServiceUtil.returnError(
                        UtilProperties.getMessage(resource, "AccountingErrorCreatingInvoiceFromOrder", locale),
                        null, null, setInvoiceStatusResult);
            }
        }

        Map<String, Object> resp = ServiceUtil.returnSuccess();
        resp.put("invoiceId", invoiceId);
        resp.put("invoiceTypeId", invoiceType);
        return resp;
    } catch (GenericEntityException e) {
        Debug.logError(e, "Entity/data problem creating invoice from order items: " + e.toString(), module);
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource, "AccountingEntityDataProblemCreatingInvoiceFromOrderItems",
                        UtilMisc.toMap("reason", e.toString()), locale));
    } catch (GenericServiceException e) {
        Debug.logError(e, "Service/other problem creating invoice from order items: " + e.toString(), module);
        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                "AccountingServiceOtherProblemCreatingInvoiceFromOrderItems",
                UtilMisc.toMap("reason", e.toString()), locale));
    }
}