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.egov.ptis.domain.service.property.PropertyService.java

/**
 * @param totalColl// w  ww .ja v  a2  s.  c  o m
 * @param newDemandDetail
 * @return
 */
private BigDecimal updateCollection(BigDecimal totalColl, final EgDemandDetails newDemandDetail) {
    BigDecimal remaining = totalColl;
    if (newDemandDetail != null) {
        newDemandDetail.setAmtCollected(ZERO);
        if (remaining.compareTo(BigDecimal.ZERO) > 0) {
            if (remaining.compareTo(newDemandDetail.getAmount()) <= 0) {
                newDemandDetail.setAmtCollected(remaining);
                newDemandDetail.setModifiedDate(new Date());
                remaining = BigDecimal.ZERO;
            } else {
                newDemandDetail.setAmtCollected(newDemandDetail.getAmount());
                newDemandDetail.setModifiedDate(new Date());
                remaining = remaining.subtract(newDemandDetail.getAmount());
            }
        }
    }
    return remaining;
}

From source file:nl.strohalm.cyclos.services.transactions.PaymentServiceImpl.java

private void insertFees(final LockHandler lockHandler, final Transfer transfer, final boolean forced,
        final BigDecimal originalAmount, final boolean simulation, final Set<ChargedFee> chargedFees) {
    final TransferType transferType = transfer.getType();
    final Account from = transfer.getFrom();
    final Account to = transfer.getTo();
    final TransactionFeeQuery query = new TransactionFeeQuery();
    query.setTransferType(transferType);
    final List<? extends TransactionFee> fees = transactionFeeService.search(query);
    BigDecimal totalPercentage = BigDecimal.ZERO;
    BigDecimal feeTotalAmount = BigDecimal.ZERO;
    Transfer topMost = getTopMost(transfer);
    final Calendar date = topMost.getDate();
    transfer.setChildren(new ArrayList<Transfer>());
    for (final TransactionFee fee : fees) {
        final Account fromAccount = fetchService.fetch(from, Account.Relationships.TYPE,
                MemberAccount.Relationships.MEMBER);
        final Account toAccount = fetchService.fetch(to, Account.Relationships.TYPE,
                MemberAccount.Relationships.MEMBER);

        final ChargedFee key = new ChargedFee(fee, fromAccount, toAccount);
        if (chargedFees.contains(key)) {
            throw new ValidationException("payment.error.circularFees");
        }/* ww w . j av  a2s .  co  m*/
        chargedFees.add(key);

        // Build the fee transfer
        final BuildTransferWithFeesDTO params = new BuildTransferWithFeesDTO(date, fromAccount, toAccount,
                originalAmount, fee, false);
        // rate stuff; buildTransfer MUST have these set.
        params.setEmissionDate(transfer.getEmissionDate());
        params.setExpirationDate(transfer.getExpirationDate());
        final Transfer feeTransfer = transactionFeeService.buildTransfer(params);

        // If the fee transfer is null, the fee should not be applied
        if (feeTransfer == null) {
            continue;
        }
        // Ensure the last fee when 100% will be the exact amount left
        if (fee instanceof SimpleTransactionFee && fee.getAmount().isPercentage()) {
            final BigDecimal feeValue = fee.getAmount().getValue();
            // Only when it's not a single fee
            if (!(totalPercentage.equals(BigDecimal.ZERO) && feeValue.doubleValue() == 100.0)) {
                totalPercentage = totalPercentage.add(feeValue);
                // TODO: shouldn't this be >= 0 in stead of == 0 (Rinke) ?
                if (totalPercentage.compareTo(new BigDecimal(100)) == 0 && feeTransfer != null) {
                    feeTransfer.setAmount(originalAmount.subtract(feeTotalAmount));
                }
            }
        }

        // Insert the fee transfer
        if (feeTransfer != null && feeTransfer.getAmount().floatValue() > PRECISION_DELTA) {
            feeTotalAmount = feeTotalAmount.add(feeTransfer.getAmount());
            feeTransfer.setParent(transfer);
            feeTransfer.setDate(transfer.getDate());
            feeTransfer.setStatus(transfer.getStatus());
            feeTransfer.setNextAuthorizationLevel(transfer.getNextAuthorizationLevel());
            feeTransfer.setProcessDate(transfer.getProcessDate());
            feeTransfer.setExternalTransfer(transfer.getExternalTransfer());
            feeTransfer.setBy(transfer.getBy());

            // Copy custom values of common custom fields from the parent to the fee transfer
            final List<PaymentCustomField> customFields = paymentCustomFieldService.list(feeTransfer.getType(),
                    false);
            if (!CollectionUtils.isEmpty(transfer.getCustomValues())) {
                final Collection<PaymentCustomFieldValue> feeTransferCustomValues = new ArrayList<PaymentCustomFieldValue>();
                for (final PaymentCustomFieldValue fieldValue : transfer.getCustomValues()) {
                    final CustomField field = fieldValue.getField();
                    if (customFields.contains(field)) {
                        final PaymentCustomFieldValue newFieldValue = new PaymentCustomFieldValue();
                        newFieldValue.setField(field);
                        newFieldValue.setValue(fieldValue.getValue());
                        feeTransferCustomValues.add(newFieldValue);
                    }
                }
                feeTransfer.setCustomValues(feeTransferCustomValues);
            }

            insertTransferAndPayFees(lockHandler, feeTransfer, forced, simulation, chargedFees);
            transfer.getChildren().add(feeTransfer);
        }
    }
}

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

public void createPaymentRequestOrCreditMemoDocument(OleInvoiceDocument inv) {
    List<OleInvoiceItem> negativeItems = new ArrayList<>();
    List<OleInvoiceItem> positiveItems = new ArrayList<>();
    List<OleInvoiceItem> lineItems = new ArrayList<>();
    List<OleInvoiceItem> positiveLineItems = new ArrayList<>();
    List<OleInvoiceItem> negativeLineItems = new ArrayList<>();
    Boolean isItemLevelDebit = null;
    Boolean isAdditionalChargeLevelDebit = null;
    Boolean isItemLevelCredit = null;
    Boolean isAdditionalChargeLevelCredit = null;
    BigDecimal firstPOTotalUnitPrice = BigDecimal.ZERO;
    for (OleInvoiceItem item : (List<OleInvoiceItem>) inv.getItems()) {
        if (item.isDebitItem() && (item.getItemListPrice().isNonZero() || (item.getItemUnitPrice() != null
                && item.getItemUnitPrice().compareTo(BigDecimal.ZERO) != 0))) {

            if (lineItems.size() == 0 && item.getPurchaseOrderIdentifier() != null) {
                lineItems.add(item);//from w w w .  ja  va 2 s.  c  o  m
                firstPOTotalUnitPrice = firstPOTotalUnitPrice.add(item.getItemUnitPrice());
            } else if (lineItems.size() > 0 && item.getPurchaseOrderIdentifier() != null && lineItems.get(0)
                    .getPurchaseOrderIdentifier().compareTo(item.getPurchaseOrderIdentifier()) == 0) {
                lineItems.add(item);
                firstPOTotalUnitPrice = firstPOTotalUnitPrice.add(item.getItemUnitPrice());
            }

            if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
                if (isItemLevelDebit == null) {
                    isItemLevelDebit = true;
                }
                isItemLevelDebit &= item.isDebitItem();

                if (lineItems.size() > 0 && item.getItemListPrice().isNonZero()) {
                    positiveLineItems.add(item);
                }
            }
            if (item.getItemType().isAdditionalChargeIndicator()) {
                if (isAdditionalChargeLevelDebit == null) {
                    isAdditionalChargeLevelDebit = true;
                }
                isAdditionalChargeLevelDebit &= item.isDebitItem();
                firstPOTotalUnitPrice = firstPOTotalUnitPrice.add(item.getItemUnitPrice());

            }
            if (item.getItemListPrice().isNonZero()) {
                positiveItems.add(item);
            }

        } else if (!item.isDebitItem()
                && (item.getItemListPrice().isNonZero() || (item.getItemUnitPrice() != null
                        && item.getItemUnitPrice().compareTo(BigDecimal.ZERO) != 0))) {

            if (lineItems.size() == 0 && item.getPurchaseOrderIdentifier() != null) {
                lineItems.add(item);
                firstPOTotalUnitPrice = firstPOTotalUnitPrice.subtract(item.getItemUnitPrice());
            } else if (lineItems.size() > 0 && item.getPurchaseOrderIdentifier() != null && lineItems.get(0)
                    .getPurchaseOrderIdentifier().compareTo(item.getPurchaseOrderIdentifier()) == 0) {
                lineItems.add(item);
                firstPOTotalUnitPrice = firstPOTotalUnitPrice.subtract(item.getItemUnitPrice());
            }

            if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
                if (isItemLevelCredit == null) {
                    isItemLevelCredit = true;
                }
                isItemLevelCredit &= !item.isDebitItem();

                if (lineItems.size() > 0 && item.getItemListPrice().isNonZero()) {
                    negativeLineItems.add(item);
                }
            }
            if (item.getItemType().isAdditionalChargeIndicator()) {
                if (isAdditionalChargeLevelCredit == null) {
                    isAdditionalChargeLevelCredit = true;
                }
                isAdditionalChargeLevelCredit &= !item.isDebitItem();
                firstPOTotalUnitPrice = firstPOTotalUnitPrice.subtract(item.getItemUnitPrice());

            }
            if (item.getItemListPrice().isNonZero()) {
                negativeItems.add(item);
            }
        }
    }
    positiveLineItems.removeAll(lineItems);
    negativeLineItems.removeAll(lineItems);
    if ((isItemLevelDebit == null && isAdditionalChargeLevelDebit != null && isAdditionalChargeLevelDebit)
            || (isAdditionalChargeLevelDebit == null && isItemLevelDebit != null && isItemLevelDebit)
            || (isItemLevelCredit == null && isAdditionalChargeLevelCredit != null
                    && isAdditionalChargeLevelCredit)
            || (isAdditionalChargeLevelCredit == null && isItemLevelCredit != null && isItemLevelCredit)
                    && !(isItemLevelCredit != null && isItemLevelCredit && isItemLevelDebit != null
                            && isItemLevelDebit)) {
        if (new KualiDecimal(firstPOTotalUnitPrice).isNegative()) {
            createCreditMemoDocument(inv, lineItems, true);
        } else {
            createPaymentRequestDocument(inv, lineItems, true);
        }
        if (positiveLineItems.size() > 0) {
            createPaymentRequestDocument(inv, positiveLineItems, false);
        }
        if (negativeLineItems.size() > 0) {
            createCreditMemoDocument(inv, negativeLineItems, false);
        }
    } else {
        if (positiveItems.size() > 0) {
            createPaymentRequestDocument(inv, positiveItems, false);
        }
        if (negativeItems.size() > 0) {
            createCreditMemoDocument(inv, negativeItems, false);
        }
    }
}

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

public static Map<String, Object> createInvoicesFromShipments(DispatchContext dctx,
        Map<String, ? extends Object> context) {
    Delegator delegator = dctx.getDelegator();
    LocalDispatcher dispatcher = dctx.getDispatcher();
    List<String> shipmentIds = UtilGenerics.checkList(context.get("shipmentIds"));
    Locale locale = (Locale) context.get("locale");
    Boolean createSalesInvoicesForDropShipments = (Boolean) context.get("createSalesInvoicesForDropShipments");
    if (UtilValidate.isEmpty(createSalesInvoicesForDropShipments))
        createSalesInvoicesForDropShipments = Boolean.FALSE;

    boolean salesShipmentFound = false;
    boolean purchaseShipmentFound = false;
    boolean dropShipmentFound = false;

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

    //DEJ20060520: not used? planned to be used? List shipmentIdList = new LinkedList();
    for (String tmpShipmentId : shipmentIds) {
        try {/*from w ww . j  a  va2s  . c  om*/
            GenericValue shipment = EntityQuery.use(delegator).from("Shipment")
                    .where("shipmentId", tmpShipmentId).queryOne();
            if ((shipment.getString("shipmentTypeId") != null)
                    && (shipment.getString("shipmentTypeId").equals("PURCHASE_SHIPMENT"))) {
                purchaseShipmentFound = true;
            } else if ((shipment.getString("shipmentTypeId") != null)
                    && (shipment.getString("shipmentTypeId").equals("DROP_SHIPMENT"))) {
                dropShipmentFound = true;
            } else {
                salesShipmentFound = true;
            }
            if (purchaseShipmentFound && salesShipmentFound && dropShipmentFound) {
                return ServiceUtil.returnError(UtilProperties.getMessage(
                        resource, "AccountingShipmentsOfDifferentTypes", UtilMisc.toMap("tmpShipmentId",
                                tmpShipmentId, "shipmentTypeId", shipment.getString("shipmentTypeId")),
                        locale));
            }
        } catch (GenericEntityException e) {
            Debug.logError(e, "Trouble getting Shipment entity for shipment " + tmpShipmentId, module);
            return ServiceUtil
                    .returnError(UtilProperties.getMessage(resource, "AccountingTroubleGettingShipmentEntity",
                            UtilMisc.toMap("tmpShipmentId", tmpShipmentId), locale));
        }
    }
    EntityQuery shipmentQuery = EntityQuery.use(delegator)
            .where(EntityCondition.makeCondition("shipmentId", EntityOperator.IN, shipmentIds))
            .orderBy("shipmentId");
    // check the status of the shipment

    // get the items of the shipment.  They can come from ItemIssuance if the shipment were from a sales order, ShipmentReceipt
    // if it were a purchase order or from the order items of the (possibly linked) orders if the shipment is a drop shipment
    List<GenericValue> items = null;
    List<GenericValue> orderItemAssocs = null;
    try {
        if (purchaseShipmentFound) {
            items = shipmentQuery.from("ShipmentReceipt").queryList();
            // filter out items which have been received but are not actually owned by an internal organization, so they should not be on a purchase invoice
            Iterator<GenericValue> itemsIter = items.iterator();
            while (itemsIter.hasNext()) {
                GenericValue item = itemsIter.next();
                GenericValue inventoryItem = item.getRelatedOne("InventoryItem", false);
                GenericValue ownerPartyRole = EntityQuery.use(delegator).from("PartyRole").where("partyId",
                        inventoryItem.get("ownerPartyId"), "roleTypeId", "INTERNAL_ORGANIZATIO").cache()
                        .queryOne();
                if (UtilValidate.isEmpty(ownerPartyRole)) {
                    itemsIter.remove();
                }
            }
        } else if (dropShipmentFound) {

            List<GenericValue> shipments = shipmentQuery.from("Shipment").queryList();

            // Get the list of purchase order IDs related to the shipments
            List<String> purchaseOrderIds = EntityUtil.getFieldListFromEntityList(shipments, "primaryOrderId",
                    true);

            if (createSalesInvoicesForDropShipments) {

                // If a sales invoice is being created for a drop shipment, we have to reference the original sales order items
                // Get the list of the linked orderIds (original sales orders)
                orderItemAssocs = EntityQuery.use(delegator).from("OrderItemAssoc")
                        .where(EntityCondition.makeCondition("toOrderId", EntityOperator.IN, purchaseOrderIds))
                        .queryList();

                // Get only the order items which are indirectly related to the purchase order - this limits the list to the drop ship group(s)
                items = EntityUtil.getRelated("FromOrderItem", null, orderItemAssocs, false);
            } else {

                // If it's a purchase invoice being created, the order items for that purchase orders can be used directly
                items = EntityQuery.use(delegator).from("OrderItem")
                        .where(EntityCondition.makeCondition("orderId", EntityOperator.IN, purchaseOrderIds))
                        .queryList();
            }
        } else {
            items = shipmentQuery.from("ItemIssuance").queryList();
        }
    } catch (GenericEntityException e) {
        Debug.logError(e, "Problem getting issued items from shipments", module);
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource, "AccountingProblemGettingItemsFromShipments", locale));
    }
    if (items.size() == 0) {
        Debug.logInfo("No items issued for shipments", module);
        return ServiceUtil.returnSuccess();
    }

    // group items by order
    Map<String, List<GenericValue>> shippedOrderItems = FastMap.newInstance();
    for (GenericValue item : items) {
        String orderId = item.getString("orderId");
        String orderItemSeqId = item.getString("orderItemSeqId");
        List<GenericValue> itemsByOrder = shippedOrderItems.get(orderId);
        if (itemsByOrder == null) {
            itemsByOrder = FastList.newInstance();
        }

        // check and make sure we haven't already billed for this issuance or shipment receipt
        List<EntityCondition> billFields = FastList.newInstance();
        billFields.add(EntityCondition.makeCondition("orderId", orderId));
        billFields.add(EntityCondition.makeCondition("orderItemSeqId", orderItemSeqId));
        billFields
                .add(EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "INVOICE_CANCELLED"));

        if (dropShipmentFound) {

            // Drop shipments have neither issuances nor receipts, so this check is meaningless
            itemsByOrder.add(item);
            shippedOrderItems.put(orderId, itemsByOrder);
            continue;
        } else if (item.getEntityName().equals("ItemIssuance")) {
            billFields.add(EntityCondition.makeCondition("itemIssuanceId", item.get("itemIssuanceId")));
        } else if (item.getEntityName().equals("ShipmentReceipt")) {
            billFields.add(EntityCondition.makeCondition("shipmentReceiptId", item.getString("receiptId")));
        }
        List<GenericValue> itemBillings = null;
        try {
            itemBillings = EntityQuery.use(delegator).from("OrderItemBillingAndInvoiceAndItem")
                    .where(billFields).queryList();
        } catch (GenericEntityException e) {
            Debug.logError(e, "Problem looking up OrderItemBilling records for " + billFields, module);
            return ServiceUtil.returnError(
                    UtilProperties.getMessage(resource, "AccountingProblemLookingUpOrderItemBilling",
                            UtilMisc.toMap("billFields", billFields), locale));
        }

        // if none found, then okay to bill
        if (itemBillings.size() == 0) {
            itemsByOrder.add(item);
        }

        // update the map with modified list
        shippedOrderItems.put(orderId, itemsByOrder);
    }

    // make sure we aren't billing items already invoiced i.e. items billed as digital (FINDIG)
    Set<String> orders = shippedOrderItems.keySet();
    for (String orderId : orders) {

        // we'll only use this list to figure out which ones to send
        List<GenericValue> billItems = shippedOrderItems.get(orderId);

        // a new list to be used to pass to the create invoice service
        List<GenericValue> toBillItems = FastList.newInstance();

        // map of available quantities so we only have to calc once
        Map<String, BigDecimal> itemQtyAvail = FastMap.newInstance();

        // now we will check each issuance and make sure it hasn't already been billed
        for (GenericValue issue : billItems) {
            BigDecimal issueQty = ZERO;

            if (issue.getEntityName().equals("ShipmentReceipt")) {
                issueQty = issue.getBigDecimal("quantityAccepted");
            } else {
                issueQty = issue.getBigDecimal("quantity");
            }

            BigDecimal billAvail = itemQtyAvail.get(issue.getString("orderItemSeqId"));
            if (billAvail == null) {
                List<EntityCondition> lookup = FastList.newInstance();
                lookup.add(EntityCondition.makeCondition("orderId", orderId));
                lookup.add(EntityCondition.makeCondition("orderItemSeqId", issue.get("orderItemSeqId")));
                lookup.add(EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL,
                        "INVOICE_CANCELLED"));
                GenericValue orderItem = null;
                List<GenericValue> billed = null;
                BigDecimal orderedQty = null;
                try {
                    orderItem = issue.getEntityName().equals("OrderItem") ? issue
                            : issue.getRelatedOne("OrderItem", false);

                    // total ordered
                    orderedQty = orderItem.getBigDecimal("quantity");

                    if (dropShipmentFound && createSalesInvoicesForDropShipments.booleanValue()) {

                        // Override the issueQty with the quantity from the purchase order item
                        GenericValue orderItemAssoc = EntityUtil.getFirst(EntityUtil.filterByAnd(
                                orderItemAssocs, UtilMisc.toMap("orderId", issue.getString("orderId"),
                                        "orderItemSeqId", issue.getString("orderItemSeqId"))));
                        GenericValue purchaseOrderItem = orderItemAssoc.getRelatedOne("ToOrderItem", false);
                        orderItem.set("quantity", purchaseOrderItem.getBigDecimal("quantity"));
                        issueQty = purchaseOrderItem.getBigDecimal("quantity");
                    }
                    billed = EntityQuery.use(delegator).from("OrderItemBillingAndInvoiceAndItem").where(lookup)
                            .queryList();
                } catch (GenericEntityException e) {
                    Debug.logError(e, "Problem getting OrderItem/OrderItemBilling records " + lookup, module);
                    return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                            "AccountingProblemGettingOrderItemOrderItemBilling",
                            UtilMisc.toMap("lookup", lookup), locale));
                }

                // add up the already billed total
                if (billed.size() > 0) {
                    BigDecimal billedQuantity = ZERO;
                    for (GenericValue oib : billed) {
                        BigDecimal qty = oib.getBigDecimal("quantity");
                        if (qty != null) {
                            billedQuantity = billedQuantity.add(qty).setScale(DECIMALS, ROUNDING);
                        }
                    }
                    BigDecimal leftToBill = orderedQty.subtract(billedQuantity).setScale(DECIMALS, ROUNDING);
                    billAvail = leftToBill;
                } else {
                    billAvail = orderedQty;
                }
            }

            // no available means we cannot bill anymore
            if (billAvail != null && billAvail.signum() == 1) { // this checks if billAvail is a positive non-zero number
                if (issueQty != null && issueQty.compareTo(billAvail) > 0) {
                    // can only bill some of the issuance; others have been billed already
                    if ("ShipmentReceipt".equals(issue.getEntityName())) {
                        issue.set("quantityAccepted", billAvail);
                    } else {
                        issue.set("quantity", billAvail);
                    }
                    billAvail = ZERO;
                } else {
                    // now have been billed
                    billAvail = billAvail.subtract(issueQty).setScale(DECIMALS, ROUNDING);
                }

                // okay to bill these items; but none else
                toBillItems.add(issue);
            }

            // update the available to bill quantity for the next pass
            itemQtyAvail.put(issue.getString("orderItemSeqId"), billAvail);
        }

        OrderReadHelper orh = new OrderReadHelper(delegator, orderId);

        GenericValue productStore = orh.getProductStore();
        String prorateShipping = productStore != null ? productStore.getString("prorateShipping") : "N";

        // If shipping charges are not prorated, the shipments need to be examined for additional shipping charges
        if ("N".equalsIgnoreCase(prorateShipping)) {

            // Get the set of filtered shipments
            List<GenericValue> invoiceableShipments = null;
            try {
                if (dropShipmentFound) {

                    List<String> invoiceablePrimaryOrderIds = null;
                    if (createSalesInvoicesForDropShipments) {

                        // If a sales invoice is being created for the drop shipment, we need to reference back to the original purchase order IDs

                        // Get the IDs for orders which have billable items
                        List<String> invoiceableLinkedOrderIds = EntityUtil
                                .getFieldListFromEntityList(toBillItems, "orderId", true);

                        // Get back the IDs of the purchase orders - this will be a list of the purchase order items which are billable by virtue of not having been
                        //  invoiced in a previous sales invoice
                        List<GenericValue> reverseOrderItemAssocs = EntityUtil
                                .filterByCondition(orderItemAssocs, EntityCondition.makeCondition("orderId",
                                        EntityOperator.IN, invoiceableLinkedOrderIds));
                        invoiceablePrimaryOrderIds = EntityUtil
                                .getFieldListFromEntityList(reverseOrderItemAssocs, "toOrderId", true);

                    } else {

                        // If a purchase order is being created for a drop shipment, the purchase order IDs can be used directly
                        invoiceablePrimaryOrderIds = EntityUtil.getFieldListFromEntityList(toBillItems,
                                "orderId", true);

                    }

                    // Get the list of shipments which are associated with the filtered purchase orders
                    if (!UtilValidate.isEmpty(invoiceablePrimaryOrderIds)) {
                        invoiceableShipments = EntityQuery.use(delegator).from("Shipment")
                                .where(UtilMisc.toList(
                                        EntityCondition.makeCondition("primaryOrderId", EntityOperator.IN,
                                                invoiceablePrimaryOrderIds),
                                        EntityCondition.makeCondition("shipmentId", EntityOperator.IN,
                                                shipmentIds)))
                                .queryList();
                    }
                } else {
                    List<String> invoiceableShipmentIds = EntityUtil.getFieldListFromEntityList(toBillItems,
                            "shipmentId", true);
                    if (UtilValidate.isNotEmpty(invoiceableShipmentIds)) {
                        invoiceableShipments = EntityQuery
                                .use(delegator).from("Shipment").where(EntityCondition
                                        .makeCondition("shipmentId", EntityOperator.IN, invoiceableShipmentIds))
                                .queryList();
                    }
                }
            } catch (GenericEntityException e) {
                Debug.logError(e, "Trouble calling createInvoicesFromShipments service", module);
                return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                        "AccountingTroubleCallingCreateInvoicesFromShipmentsService", locale));
            }

            // Total the additional shipping charges for the shipments
            Map<GenericValue, BigDecimal> additionalShippingCharges = FastMap.newInstance();
            BigDecimal totalAdditionalShippingCharges = ZERO;
            if (UtilValidate.isNotEmpty(invoiceableShipments)) {
                for (GenericValue shipment : invoiceableShipments) {
                    if (shipment.get("additionalShippingCharge") == null)
                        continue;
                    BigDecimal shipmentAdditionalShippingCharges = shipment
                            .getBigDecimal("additionalShippingCharge").setScale(DECIMALS, ROUNDING);
                    additionalShippingCharges.put(shipment, shipmentAdditionalShippingCharges);
                    totalAdditionalShippingCharges = totalAdditionalShippingCharges
                            .add(shipmentAdditionalShippingCharges);
                }
            }

            // If the additional shipping charges are greater than zero, process them
            if (totalAdditionalShippingCharges.signum() == 1) {

                // Add an OrderAdjustment to the order for each additional shipping charge
                for (Map.Entry<GenericValue, BigDecimal> entry : additionalShippingCharges.entrySet()) {
                    GenericValue shipment = entry.getKey();
                    BigDecimal additionalShippingCharge = entry.getValue();
                    String shipmentId = shipment.getString("shipmentId");
                    Map<String, Object> createOrderAdjustmentContext = FastMap.newInstance();
                    createOrderAdjustmentContext.put("orderId", orderId);
                    createOrderAdjustmentContext.put("orderAdjustmentTypeId", "SHIPPING_CHARGES");
                    String addtlChargeDescription = shipment.getString("addtlShippingChargeDesc");
                    if (UtilValidate.isEmpty(addtlChargeDescription)) {
                        addtlChargeDescription = UtilProperties.getMessage(resource,
                                "AccountingAdditionalShippingChargeForShipment",
                                UtilMisc.toMap("shipmentId", shipmentId), locale);
                    }
                    createOrderAdjustmentContext.put("description", addtlChargeDescription);
                    createOrderAdjustmentContext.put("sourceReferenceId", shipmentId);
                    createOrderAdjustmentContext.put("amount", additionalShippingCharge);
                    createOrderAdjustmentContext.put("userLogin", context.get("userLogin"));
                    String shippingOrderAdjustmentId = null;
                    try {
                        Map<String, Object> createOrderAdjustmentResult = dispatcher
                                .runSync("createOrderAdjustment", createOrderAdjustmentContext);
                        shippingOrderAdjustmentId = (String) createOrderAdjustmentResult
                                .get("orderAdjustmentId");
                    } catch (GenericServiceException e) {
                        Debug.logError(e, "Trouble calling createOrderAdjustment service", module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingTroubleCallingCreateOrderAdjustmentService", locale));
                    }

                    // Obtain a list of OrderAdjustments due to tax on the shipping charges, if any
                    GenericValue billToParty = orh.getBillToParty();
                    GenericValue payToParty = orh.getBillFromParty();
                    GenericValue destinationContactMech = null;
                    try {
                        destinationContactMech = shipment.getRelatedOne("DestinationPostalAddress", false);
                    } catch (GenericEntityException e) {
                        Debug.logError(e,
                                "Trouble calling createInvoicesFromShipment service; invoice not created for shipment "
                                        + shipmentId,
                                module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingTroubleCallingCreateInvoicesFromShipmentService", locale));
                    }

                    List<Object> emptyList = FastList.newInstance();
                    Map<String, Object> calcTaxContext = FastMap.newInstance();
                    calcTaxContext.put("productStoreId", orh.getProductStoreId());
                    calcTaxContext.put("payToPartyId", payToParty.getString("partyId"));
                    calcTaxContext.put("billToPartyId", billToParty.getString("partyId"));
                    calcTaxContext.put("orderShippingAmount", totalAdditionalShippingCharges);
                    calcTaxContext.put("shippingAddress", destinationContactMech);

                    // These parameters don't matter if we're only worried about adjustments on the shipping charges
                    calcTaxContext.put("itemProductList", emptyList);
                    calcTaxContext.put("itemAmountList", emptyList);
                    calcTaxContext.put("itemPriceList", emptyList);
                    calcTaxContext.put("itemQuantityList", emptyList);
                    calcTaxContext.put("itemShippingList", emptyList);

                    Map<String, Object> calcTaxResult = null;
                    try {
                        calcTaxResult = dispatcher.runSync("calcTax", calcTaxContext);
                    } catch (GenericServiceException e) {
                        Debug.logError(e, "Trouble calling calcTaxService", module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingTroubleCallingCalcTaxService", locale));
                    }
                    List<GenericValue> orderAdjustments = UtilGenerics
                            .checkList(calcTaxResult.get("orderAdjustments"));

                    // If we have any OrderAdjustments due to tax on shipping, store them and add them to the total
                    if (orderAdjustments != null) {
                        for (GenericValue orderAdjustment : orderAdjustments) {
                            totalAdditionalShippingCharges = totalAdditionalShippingCharges
                                    .add(orderAdjustment.getBigDecimal("amount").setScale(DECIMALS, ROUNDING));
                            orderAdjustment.set("orderAdjustmentId", delegator.getNextSeqId("OrderAdjustment"));
                            orderAdjustment.set("orderId", orderId);
                            orderAdjustment.set("orderItemSeqId", "_NA_");
                            orderAdjustment.set("shipGroupSeqId", shipment.getString("primaryShipGroupSeqId"));
                            orderAdjustment.set("originalAdjustmentId", shippingOrderAdjustmentId);
                        }
                        try {
                            delegator.storeAll(orderAdjustments);
                        } catch (GenericEntityException e) {
                            Debug.logError(e, "Problem storing OrderAdjustments: " + orderAdjustments, module);
                            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                    "AccountingProblemStoringOrderAdjustments",
                                    UtilMisc.toMap("orderAdjustments", orderAdjustments), locale));
                        }
                    }

                    // If part of the order was paid via credit card, try to charge it for the additional shipping
                    List<GenericValue> orderPaymentPreferences = null;
                    try {
                        orderPaymentPreferences = EntityQuery.use(delegator).from("OrderPaymentPreference")
                                .where("orderId", orderId, "paymentMethodTypeId", "CREDIT_CARD").queryList();
                    } catch (GenericEntityException e) {
                        Debug.logError(e, "Problem getting OrderPaymentPreference records", module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingProblemGettingOrderPaymentPreferences", locale));
                    }

                    //  Use the first credit card we find, for the sake of simplicity
                    String paymentMethodId = null;
                    GenericValue cardOrderPaymentPref = EntityUtil.getFirst(orderPaymentPreferences);
                    if (cardOrderPaymentPref != null) {
                        paymentMethodId = cardOrderPaymentPref.getString("paymentMethodId");
                    }

                    if (paymentMethodId != null) {

                        // Release all outstanding (not settled or cancelled) authorizations, while keeping a running
                        //  total of their amounts so that the total plus the additional shipping charges can be authorized again
                        //  all at once.
                        BigDecimal totalNewAuthAmount = totalAdditionalShippingCharges.setScale(DECIMALS,
                                ROUNDING);
                        for (GenericValue orderPaymentPreference : orderPaymentPreferences) {
                            if (!(orderPaymentPreference.getString("statusId").equals("PAYMENT_SETTLED")
                                    || orderPaymentPreference.getString("statusId")
                                            .equals("PAYMENT_CANCELLED"))) {
                                GenericValue authTransaction = PaymentGatewayServices
                                        .getAuthTransaction(orderPaymentPreference);
                                if (authTransaction != null && authTransaction.get("amount") != null) {

                                    // Update the total authorized amount
                                    totalNewAuthAmount = totalNewAuthAmount.add(authTransaction
                                            .getBigDecimal("amount").setScale(DECIMALS, ROUNDING));

                                    // Release the authorization for the OrderPaymentPreference
                                    Map<String, Object> prefReleaseResult = null;
                                    try {
                                        prefReleaseResult = dispatcher.runSync("releaseOrderPaymentPreference",
                                                UtilMisc.toMap("orderPaymentPreferenceId",
                                                        orderPaymentPreference
                                                                .getString("orderPaymentPreferenceId"),
                                                        "userLogin", context.get("userLogin")));
                                    } catch (GenericServiceException e) {
                                        Debug.logError(e,
                                                "Trouble calling releaseOrderPaymentPreference service",
                                                module);
                                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                                "AccountingTroubleCallingReleaseOrderPaymentPreferenceService",
                                                locale));
                                    }
                                    if (ServiceUtil.isError(prefReleaseResult)
                                            || ServiceUtil.isFailure(prefReleaseResult)) {
                                        String errMsg = ServiceUtil.getErrorMessage(prefReleaseResult);
                                        Debug.logError(errMsg, module);
                                        return ServiceUtil.returnError(errMsg);
                                    }
                                }
                            }
                        }

                        // Create a new OrderPaymentPreference for the order to handle the new (totalled) charge. Don't
                        //  set the maxAmount so that it doesn't interfere with other authorizations
                        Map<String, Object> serviceContext = UtilMisc.toMap("orderId", orderId,
                                "paymentMethodId", paymentMethodId, "paymentMethodTypeId", "CREDIT_CARD",
                                "userLogin", context.get("userLogin"));
                        String orderPaymentPreferenceId = null;
                        try {
                            Map<String, Object> result = dispatcher.runSync("createOrderPaymentPreference",
                                    serviceContext);
                            orderPaymentPreferenceId = (String) result.get("orderPaymentPreferenceId");
                        } catch (GenericServiceException e) {
                            Debug.logError(e, "Trouble calling createOrderPaymentPreference service", module);
                            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                    "AccountingTroubleCallingCreateOrderPaymentPreferenceService", locale));
                        }

                        // Attempt to authorize the new orderPaymentPreference
                        Map<String, Object> authResult = null;
                        try {
                            // Use an overrideAmount because the maxAmount wasn't set on the OrderPaymentPreference
                            authResult = dispatcher.runSync("authOrderPaymentPreference",
                                    UtilMisc.toMap("orderPaymentPreferenceId", orderPaymentPreferenceId,
                                            "overrideAmount", totalNewAuthAmount, "userLogin",
                                            context.get("userLogin")));
                        } catch (GenericServiceException e) {
                            Debug.logError(e, "Trouble calling authOrderPaymentPreference service", module);
                            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                    "AccountingTroubleCallingAuthOrderPaymentPreferenceService", locale));
                        }

                        // If the authorization fails, create the invoice anyway, but make a note of it
                        boolean authFinished = ((Boolean) authResult.get("finished")).booleanValue();
                        boolean authErrors = ((Boolean) authResult.get("errors")).booleanValue();
                        if (authErrors || !authFinished) {
                            String errMsg = UtilProperties.getMessage(resource,
                                    "AccountingUnableToAuthAdditionalShipCharges",
                                    UtilMisc.toMap("shipmentId", shipmentId, "paymentMethodId", paymentMethodId,
                                            "orderPaymentPreferenceId", orderPaymentPreferenceId),
                                    locale);
                            Debug.logError(errMsg, module);
                        }

                    }
                }
            }
        } else {
            Debug.logInfo(UtilProperties.getMessage(resource, "AccountingIgnoringAdditionalShipCharges",
                    UtilMisc.toMap("productStoreId", orh.getProductStoreId()), locale), module);
        }

        String invoiceId = null;
        GenericValue shipmentItemBilling = null;
        String shipmentId = shipmentIds.get(0);
        try {
            shipmentItemBilling = EntityQuery.use(delegator).from("ShipmentItemBilling")
                    .where("shipmentId", shipmentId).queryFirst();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(
                    UtilProperties.getMessage(resource, "AccountingProblemGettingShipmentItemBilling", locale));
        }
        if (shipmentItemBilling != null) {
            invoiceId = shipmentItemBilling.getString("invoiceId");
        }

        // call the createInvoiceForOrder service for each order
        Map<String, Object> serviceContext = UtilMisc.toMap("orderId", orderId, "billItems", toBillItems,
                "invoiceId", invoiceId, "eventDate", context.get("eventDate"), "userLogin",
                context.get("userLogin"));
        try {
            Map<String, Object> result = dispatcher.runSync("createInvoiceForOrder", serviceContext);
            invoicesCreated.add((String) result.get("invoiceId"));
        } catch (GenericServiceException e) {
            Debug.logError(e, "Trouble calling createInvoiceForOrder service; invoice not created for shipment",
                    module);
            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                    "AccountingTroubleCallingCreateInvoiceForOrderService", locale));
        }
    }

    Map<String, Object> response = ServiceUtil.returnSuccess();
    response.put("invoicesCreated", invoicesCreated);
    return response;
}

From source file:org.meveo.service.billing.impl.InvoiceService.java

public void recomputeAggregates(Invoice invoice, User currentUser) throws BusinessException {
    boolean entreprise = invoice.getProvider().isEntreprise();
    int rounding = invoice.getProvider().getRounding() == null ? 2 : invoice.getProvider().getRounding();
    BillingAccount billingAccount = billingAccountService.findById(invoice.getBillingAccount().getId());
    boolean exoneratedFromTaxes = billingAccountService.isExonerated(billingAccount);
    BigDecimal nonEnterprisePriceWithTax = BigDecimal.ZERO;

    Map<Long, TaxInvoiceAgregate> taxInvoiceAgregateMap = new HashMap<Long, TaxInvoiceAgregate>();
    List<SubCategoryInvoiceAgregate> subCategoryInvoiceAgregates = new ArrayList<SubCategoryInvoiceAgregate>();
    invoice.setAmountTax(null);/* w w w .ja v a2s  .c om*/
    invoice.setAmountWithoutTax(null);
    invoice.setAmountWithTax(null);

    // update the aggregated subcat of an invoice
    for (InvoiceAgregate invoiceAggregate : invoice.getInvoiceAgregates()) {
        if (invoiceAggregate instanceof CategoryInvoiceAgregate) {
            invoiceAggregate.resetAmounts();
        } else if (invoiceAggregate instanceof TaxInvoiceAgregate) {
            TaxInvoiceAgregate taxInvoiceAgregate = (TaxInvoiceAgregate) invoiceAggregate;
            taxInvoiceAgregateMap.put(taxInvoiceAgregate.getTax().getId(), taxInvoiceAgregate);
        } else if (invoiceAggregate instanceof SubCategoryInvoiceAgregate) {
            subCategoryInvoiceAgregates.add((SubCategoryInvoiceAgregate) invoiceAggregate);
        }
    }

    for (TaxInvoiceAgregate taxInvoiceAgregate : taxInvoiceAgregateMap.values()) {
        taxInvoiceAgregate.setAmountWithoutTax(new BigDecimal(0));
        for (SubCategoryInvoiceAgregate subCategoryInvoiceAgregate : subCategoryInvoiceAgregates) {
            if (subCategoryInvoiceAgregate.getQuantity().signum() != 0) {
                if (subCategoryInvoiceAgregate.getSubCategoryTaxes().contains(taxInvoiceAgregate.getTax())) {
                    taxInvoiceAgregate.addAmountWithoutTax(subCategoryInvoiceAgregate.getAmountWithoutTax());
                }
            }
        }

        taxInvoiceAgregate.setAmountTax(taxInvoiceAgregate.getAmountWithoutTax()
                .multiply(taxInvoiceAgregate.getTaxPercent()).divide(new BigDecimal("100")));
        // then round the tax
        taxInvoiceAgregate
                .setAmountTax(taxInvoiceAgregate.getAmountTax().setScale(rounding, RoundingMode.HALF_UP));

        taxInvoiceAgregate.setAmountWithTax(
                taxInvoiceAgregate.getAmountWithoutTax().add(taxInvoiceAgregate.getAmountTax()));
    }

    // update the amount with and without tax of all the tax aggregates in
    // each sub category aggregate
    SubCategoryInvoiceAgregate biggestSubCat = null;
    BigDecimal biggestAmount = new BigDecimal("-100000000");

    for (InvoiceAgregate invoiceAgregate : subCategoryInvoiceAgregates) {
        SubCategoryInvoiceAgregate subCategoryInvoiceAgregate = (SubCategoryInvoiceAgregate) invoiceAgregate;

        if (!entreprise) {
            nonEnterprisePriceWithTax = nonEnterprisePriceWithTax
                    .add(subCategoryInvoiceAgregate.getAmountWithTax());
        }

        subCategoryInvoiceAgregate.setAmountWithoutTax(subCategoryInvoiceAgregate.getAmountWithoutTax() != null
                ? subCategoryInvoiceAgregate.getAmountWithoutTax().setScale(rounding, RoundingMode.HALF_UP)
                : BigDecimal.ZERO);

        subCategoryInvoiceAgregate.getCategoryInvoiceAgregate()
                .addAmountWithoutTax(subCategoryInvoiceAgregate.getAmountWithoutTax());

        if (subCategoryInvoiceAgregate.getAmountWithoutTax().compareTo(biggestAmount) > 0) {
            biggestAmount = subCategoryInvoiceAgregate.getAmountWithoutTax();
            biggestSubCat = subCategoryInvoiceAgregate;
        }
    }

    for (InvoiceAgregate invoiceAgregate : invoice.getInvoiceAgregates()) {
        if (invoiceAgregate instanceof CategoryInvoiceAgregate) {
            CategoryInvoiceAgregate categoryInvoiceAgregate = (CategoryInvoiceAgregate) invoiceAgregate;
            invoice.addAmountWithoutTax(
                    categoryInvoiceAgregate.getAmountWithoutTax().setScale(rounding, RoundingMode.HALF_UP));
        }

        if (invoiceAgregate instanceof TaxInvoiceAgregate) {
            TaxInvoiceAgregate taxInvoiceAgregate = (TaxInvoiceAgregate) invoiceAgregate;
            invoice.addAmountTax(taxInvoiceAgregate.getAmountTax().setScale(rounding, RoundingMode.HALF_UP));
        }
    }

    if (invoice.getAmountWithoutTax() != null) {
        invoice.setAmountWithTax(invoice.getAmountWithoutTax()
                .add(invoice.getAmountTax() == null ? BigDecimal.ZERO : invoice.getAmountTax()));
    }

    if (!entreprise && biggestSubCat != null && !exoneratedFromTaxes) {
        BigDecimal delta = nonEnterprisePriceWithTax.subtract(invoice.getAmountWithTax());
        log.debug("delta={}-{}={}", nonEnterprisePriceWithTax, invoice.getAmountWithTax(), delta);

        biggestSubCat.setAmountWithoutTax(
                biggestSubCat.getAmountWithoutTax().add(delta).setScale(rounding, RoundingMode.HALF_UP));
        for (Tax tax : biggestSubCat.getSubCategoryTaxes()) {
            TaxInvoiceAgregate invoiceAgregateT = taxInvoiceAgregateMap.get(tax.getId());
            log.debug("tax3 ht={}", invoiceAgregateT.getAmountWithoutTax());

            invoiceAgregateT.setAmountWithoutTax(
                    invoiceAgregateT.getAmountWithoutTax().add(delta).setScale(rounding, RoundingMode.HALF_UP));
            log.debug("tax4 ht={}", invoiceAgregateT.getAmountWithoutTax());

        }

        CategoryInvoiceAgregate invoiceAgregateR = biggestSubCat.getCategoryInvoiceAgregate();
        invoiceAgregateR.setAmountWithoutTax(
                invoiceAgregateR.getAmountWithoutTax().add(delta).setScale(rounding, RoundingMode.HALF_UP));

        invoice.setAmountWithoutTax(
                invoice.getAmountWithoutTax().add(delta).setScale(rounding, RoundingMode.HALF_UP));
        invoice.setAmountWithTax(nonEnterprisePriceWithTax.setScale(rounding, RoundingMode.HALF_UP));
    }

    // calculate discounts here
    // no need to create discount aggregates we will use the one from
    // adjustedInvoice

    Object[] object = invoiceAgregateService.findTotalAmountsForDiscountAggregates(getLinkedInvoice(invoice));
    BigDecimal discountAmountWithoutTax = (BigDecimal) object[0];
    BigDecimal discountAmountTax = (BigDecimal) object[1];
    BigDecimal discountAmountWithTax = (BigDecimal) object[2];

    log.debug("discountAmountWithoutTax= {}, discountAmountTax={}, discountAmountWithTax={}", object[0],
            object[1], object[2]);

    invoice.addAmountWithoutTax(discountAmountWithoutTax);
    invoice.addAmountTax(discountAmountTax);
    invoice.addAmountWithTax(discountAmountWithTax);

    // compute net to pay
    BigDecimal netToPay = BigDecimal.ZERO;
    if (entreprise) {
        netToPay = invoice.getAmountWithTax();
    } else {
        BigDecimal balance = customerAccountService.customerAccountBalanceDue(null,
                invoice.getBillingAccount().getCustomerAccount().getCode(), invoice.getDueDate(),
                invoice.getProvider());

        if (balance == null) {
            throw new BusinessException("account balance calculation failed");
        }
        netToPay = invoice.getAmountWithTax().add(balance);
    }

    invoice.setNetToPay(netToPay);
}

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

public static Map<String, Object> createInvoicesFromShipments(DispatchContext dctx,
        Map<String, ? extends Object> context) {
    Delegator delegator = dctx.getDelegator();
    LocalDispatcher dispatcher = dctx.getDispatcher();
    List<String> shipmentIds = UtilGenerics.checkList(context.get("shipmentIds"));
    Locale locale = (Locale) context.get("locale");
    Boolean createSalesInvoicesForDropShipments = (Boolean) context.get("createSalesInvoicesForDropShipments");
    if (UtilValidate.isEmpty(createSalesInvoicesForDropShipments))
        createSalesInvoicesForDropShipments = Boolean.FALSE;

    boolean salesShipmentFound = false;
    boolean purchaseShipmentFound = false;
    boolean dropShipmentFound = false;

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

    //DEJ20060520: not used? planned to be used? List shipmentIdList = new LinkedList();
    for (String tmpShipmentId : shipmentIds) {
        try {/*from www.ja va2  s .c om*/
            GenericValue shipment = EntityQuery.use(delegator).from("Shipment")
                    .where("shipmentId", tmpShipmentId).queryOne();
            if ((shipment.getString("shipmentTypeId") != null)
                    && (shipment.getString("shipmentTypeId").equals("PURCHASE_SHIPMENT"))) {
                purchaseShipmentFound = true;
            } else if ((shipment.getString("shipmentTypeId") != null)
                    && (shipment.getString("shipmentTypeId").equals("DROP_SHIPMENT"))) {
                dropShipmentFound = true;
            } else {
                salesShipmentFound = true;
            }
            if (purchaseShipmentFound && salesShipmentFound && dropShipmentFound) {
                return ServiceUtil.returnError(UtilProperties.getMessage(
                        resource, "AccountingShipmentsOfDifferentTypes", UtilMisc.toMap("tmpShipmentId",
                                tmpShipmentId, "shipmentTypeId", shipment.getString("shipmentTypeId")),
                        locale));
            }
        } catch (GenericEntityException e) {
            Debug.logError(e, "Trouble getting Shipment entity for shipment " + tmpShipmentId, module);
            return ServiceUtil
                    .returnError(UtilProperties.getMessage(resource, "AccountingTroubleGettingShipmentEntity",
                            UtilMisc.toMap("tmpShipmentId", tmpShipmentId), locale));
        }
    }
    EntityQuery shipmentQuery = EntityQuery.use(delegator)
            .where(EntityCondition.makeCondition("shipmentId", EntityOperator.IN, shipmentIds))
            .orderBy("shipmentId");
    // check the status of the shipment

    // get the items of the shipment.  They can come from ItemIssuance if the shipment were from a sales order, ShipmentReceipt
    // if it were a purchase order or from the order items of the (possibly linked) orders if the shipment is a drop shipment
    List<GenericValue> items = null;
    List<GenericValue> orderItemAssocs = null;
    try {
        if (purchaseShipmentFound) {
            items = shipmentQuery.from("ShipmentReceipt").queryList();
            // filter out items which have been received but are not actually owned by an internal organization, so they should not be on a purchase invoice
            Iterator<GenericValue> itemsIter = items.iterator();
            while (itemsIter.hasNext()) {
                GenericValue item = itemsIter.next();
                GenericValue inventoryItem = item.getRelatedOne("InventoryItem", false);
                GenericValue ownerPartyRole = EntityQuery.use(delegator).from("PartyRole").where("partyId",
                        inventoryItem.get("ownerPartyId"), "roleTypeId", "INTERNAL_ORGANIZATIO").cache()
                        .queryOne();
                if (UtilValidate.isEmpty(ownerPartyRole)) {
                    itemsIter.remove();
                }
            }
        } else if (dropShipmentFound) {

            List<GenericValue> shipments = shipmentQuery.from("Shipment").queryList();

            // Get the list of purchase order IDs related to the shipments
            List<String> purchaseOrderIds = EntityUtil.getFieldListFromEntityList(shipments, "primaryOrderId",
                    true);

            if (createSalesInvoicesForDropShipments) {

                // If a sales invoice is being created for a drop shipment, we have to reference the original sales order items
                // Get the list of the linked orderIds (original sales orders)
                orderItemAssocs = EntityQuery.use(delegator).from("OrderItemAssoc")
                        .where(EntityCondition.makeCondition("toOrderId", EntityOperator.IN, purchaseOrderIds))
                        .queryList();

                // Get only the order items which are indirectly related to the purchase order - this limits the list to the drop ship group(s)
                items = EntityUtil.getRelated("FromOrderItem", null, orderItemAssocs, false);
            } else {

                // If it's a purchase invoice being created, the order items for that purchase orders can be used directly
                items = EntityQuery.use(delegator).from("OrderItem")
                        .where(EntityCondition.makeCondition("orderId", EntityOperator.IN, purchaseOrderIds))
                        .queryList();
            }
        } else {
            items = shipmentQuery.from("ItemIssuance").queryList();
        }
    } catch (GenericEntityException e) {
        Debug.logError(e, "Problem getting issued items from shipments", module);
        return ServiceUtil.returnError(
                UtilProperties.getMessage(resource, "AccountingProblemGettingItemsFromShipments", locale));
    }
    if (items.size() == 0) {
        Debug.logInfo("No items issued for shipments", module);
        return ServiceUtil.returnSuccess();
    }

    // group items by order
    Map<String, List<GenericValue>> shippedOrderItems = new HashMap<String, List<GenericValue>>();
    for (GenericValue item : items) {
        String orderId = item.getString("orderId");
        String orderItemSeqId = item.getString("orderItemSeqId");
        List<GenericValue> itemsByOrder = shippedOrderItems.get(orderId);
        if (itemsByOrder == null) {
            itemsByOrder = new LinkedList<GenericValue>();
        }

        // check and make sure we haven't already billed for this issuance or shipment receipt
        List<EntityCondition> billFields = new LinkedList<EntityCondition>();
        billFields.add(EntityCondition.makeCondition("orderId", orderId));
        billFields.add(EntityCondition.makeCondition("orderItemSeqId", orderItemSeqId));
        billFields
                .add(EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "INVOICE_CANCELLED"));

        if (dropShipmentFound) {

            // Drop shipments have neither issuances nor receipts, so this check is meaningless
            itemsByOrder.add(item);
            shippedOrderItems.put(orderId, itemsByOrder);
            continue;
        } else if (item.getEntityName().equals("ItemIssuance")) {
            billFields.add(EntityCondition.makeCondition("itemIssuanceId", item.get("itemIssuanceId")));
        } else if (item.getEntityName().equals("ShipmentReceipt")) {
            billFields.add(EntityCondition.makeCondition("shipmentReceiptId", item.getString("receiptId")));
        }
        List<GenericValue> itemBillings = null;
        try {
            itemBillings = EntityQuery.use(delegator).from("OrderItemBillingAndInvoiceAndItem")
                    .where(billFields).queryList();
        } catch (GenericEntityException e) {
            Debug.logError(e, "Problem looking up OrderItemBilling records for " + billFields, module);
            return ServiceUtil.returnError(
                    UtilProperties.getMessage(resource, "AccountingProblemLookingUpOrderItemBilling",
                            UtilMisc.toMap("billFields", billFields), locale));
        }

        // if none found, then okay to bill
        if (itemBillings.size() == 0) {
            itemsByOrder.add(item);
        }

        // update the map with modified list
        shippedOrderItems.put(orderId, itemsByOrder);
    }

    // make sure we aren't billing items already invoiced i.e. items billed as digital (FINDIG)
    Set<String> orders = shippedOrderItems.keySet();
    for (String orderId : orders) {

        // we'll only use this list to figure out which ones to send
        List<GenericValue> billItems = shippedOrderItems.get(orderId);

        // a new list to be used to pass to the create invoice service
        List<GenericValue> toBillItems = new LinkedList<GenericValue>();

        // map of available quantities so we only have to calc once
        Map<String, BigDecimal> itemQtyAvail = new HashMap<String, BigDecimal>();

        // now we will check each issuance and make sure it hasn't already been billed
        for (GenericValue issue : billItems) {
            BigDecimal issueQty = ZERO;

            if (issue.getEntityName().equals("ShipmentReceipt")) {
                issueQty = issue.getBigDecimal("quantityAccepted");
            } else {
                issueQty = issue.getBigDecimal("quantity");
            }

            BigDecimal billAvail = itemQtyAvail.get(issue.getString("orderItemSeqId"));
            if (billAvail == null) {
                List<EntityCondition> lookup = new LinkedList<EntityCondition>();
                lookup.add(EntityCondition.makeCondition("orderId", orderId));
                lookup.add(EntityCondition.makeCondition("orderItemSeqId", issue.get("orderItemSeqId")));
                lookup.add(EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL,
                        "INVOICE_CANCELLED"));
                GenericValue orderItem = null;
                List<GenericValue> billed = null;
                BigDecimal orderedQty = null;
                try {
                    orderItem = issue.getEntityName().equals("OrderItem") ? issue
                            : issue.getRelatedOne("OrderItem", false);

                    // total ordered
                    orderedQty = orderItem.getBigDecimal("quantity");

                    if (dropShipmentFound && createSalesInvoicesForDropShipments.booleanValue()) {

                        // Override the issueQty with the quantity from the purchase order item
                        GenericValue orderItemAssoc = EntityUtil.getFirst(EntityUtil.filterByAnd(
                                orderItemAssocs, UtilMisc.toMap("orderId", issue.getString("orderId"),
                                        "orderItemSeqId", issue.getString("orderItemSeqId"))));
                        GenericValue purchaseOrderItem = orderItemAssoc.getRelatedOne("ToOrderItem", false);
                        orderItem.set("quantity", purchaseOrderItem.getBigDecimal("quantity"));
                        issueQty = purchaseOrderItem.getBigDecimal("quantity");
                    }
                    billed = EntityQuery.use(delegator).from("OrderItemBillingAndInvoiceAndItem").where(lookup)
                            .queryList();
                } catch (GenericEntityException e) {
                    Debug.logError(e, "Problem getting OrderItem/OrderItemBilling records " + lookup, module);
                    return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                            "AccountingProblemGettingOrderItemOrderItemBilling",
                            UtilMisc.toMap("lookup", lookup), locale));
                }

                // add up the already billed total
                if (billed.size() > 0) {
                    BigDecimal billedQuantity = ZERO;
                    for (GenericValue oib : billed) {
                        BigDecimal qty = oib.getBigDecimal("quantity");
                        if (qty != null) {
                            billedQuantity = billedQuantity.add(qty).setScale(DECIMALS, ROUNDING);
                        }
                    }
                    BigDecimal leftToBill = orderedQty.subtract(billedQuantity).setScale(DECIMALS, ROUNDING);
                    billAvail = leftToBill;
                } else {
                    billAvail = orderedQty;
                }
            }

            // no available means we cannot bill anymore
            if (billAvail != null && billAvail.signum() == 1) { // this checks if billAvail is a positive non-zero number
                if (issueQty != null && issueQty.compareTo(billAvail) > 0) {
                    // can only bill some of the issuance; others have been billed already
                    if ("ShipmentReceipt".equals(issue.getEntityName())) {
                        issue.set("quantityAccepted", billAvail);
                    } else {
                        issue.set("quantity", billAvail);
                    }
                    billAvail = ZERO;
                } else {
                    // now have been billed
                    billAvail = billAvail.subtract(issueQty).setScale(DECIMALS, ROUNDING);
                }

                // okay to bill these items; but none else
                toBillItems.add(issue);
            }

            // update the available to bill quantity for the next pass
            itemQtyAvail.put(issue.getString("orderItemSeqId"), billAvail);
        }

        OrderReadHelper orh = new OrderReadHelper(delegator, orderId);

        GenericValue productStore = orh.getProductStore();
        String prorateShipping = productStore != null ? productStore.getString("prorateShipping") : "N";

        // If shipping charges are not prorated, the shipments need to be examined for additional shipping charges
        if ("N".equalsIgnoreCase(prorateShipping)) {

            // Get the set of filtered shipments
            List<GenericValue> invoiceableShipments = null;
            try {
                if (dropShipmentFound) {

                    List<String> invoiceablePrimaryOrderIds = null;
                    if (createSalesInvoicesForDropShipments) {

                        // If a sales invoice is being created for the drop shipment, we need to reference back to the original purchase order IDs

                        // Get the IDs for orders which have billable items
                        List<String> invoiceableLinkedOrderIds = EntityUtil
                                .getFieldListFromEntityList(toBillItems, "orderId", true);

                        // Get back the IDs of the purchase orders - this will be a list of the purchase order items which are billable by virtue of not having been
                        //  invoiced in a previous sales invoice
                        List<GenericValue> reverseOrderItemAssocs = EntityUtil
                                .filterByCondition(orderItemAssocs, EntityCondition.makeCondition("orderId",
                                        EntityOperator.IN, invoiceableLinkedOrderIds));
                        invoiceablePrimaryOrderIds = EntityUtil
                                .getFieldListFromEntityList(reverseOrderItemAssocs, "toOrderId", true);

                    } else {

                        // If a purchase order is being created for a drop shipment, the purchase order IDs can be used directly
                        invoiceablePrimaryOrderIds = EntityUtil.getFieldListFromEntityList(toBillItems,
                                "orderId", true);

                    }

                    // Get the list of shipments which are associated with the filtered purchase orders
                    if (!UtilValidate.isEmpty(invoiceablePrimaryOrderIds)) {
                        invoiceableShipments = EntityQuery.use(delegator).from("Shipment")
                                .where(UtilMisc.toList(
                                        EntityCondition.makeCondition("primaryOrderId", EntityOperator.IN,
                                                invoiceablePrimaryOrderIds),
                                        EntityCondition.makeCondition("shipmentId", EntityOperator.IN,
                                                shipmentIds)))
                                .queryList();
                    }
                } else {
                    List<String> invoiceableShipmentIds = EntityUtil.getFieldListFromEntityList(toBillItems,
                            "shipmentId", true);
                    if (UtilValidate.isNotEmpty(invoiceableShipmentIds)) {
                        invoiceableShipments = EntityQuery
                                .use(delegator).from("Shipment").where(EntityCondition
                                        .makeCondition("shipmentId", EntityOperator.IN, invoiceableShipmentIds))
                                .queryList();
                    }
                }
            } catch (GenericEntityException e) {
                Debug.logError(e, "Trouble calling createInvoicesFromShipments service", module);
                return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                        "AccountingTroubleCallingCreateInvoicesFromShipmentsService", locale));
            }

            // Total the additional shipping charges for the shipments
            Map<GenericValue, BigDecimal> additionalShippingCharges = new HashMap<GenericValue, BigDecimal>();
            BigDecimal totalAdditionalShippingCharges = ZERO;
            if (UtilValidate.isNotEmpty(invoiceableShipments)) {
                for (GenericValue shipment : invoiceableShipments) {
                    if (shipment.get("additionalShippingCharge") == null)
                        continue;
                    BigDecimal shipmentAdditionalShippingCharges = shipment
                            .getBigDecimal("additionalShippingCharge").setScale(DECIMALS, ROUNDING);
                    additionalShippingCharges.put(shipment, shipmentAdditionalShippingCharges);
                    totalAdditionalShippingCharges = totalAdditionalShippingCharges
                            .add(shipmentAdditionalShippingCharges);
                }
            }

            // If the additional shipping charges are greater than zero, process them
            if (totalAdditionalShippingCharges.signum() == 1) {

                // Add an OrderAdjustment to the order for each additional shipping charge
                for (Map.Entry<GenericValue, BigDecimal> entry : additionalShippingCharges.entrySet()) {
                    GenericValue shipment = entry.getKey();
                    BigDecimal additionalShippingCharge = entry.getValue();
                    String shipmentId = shipment.getString("shipmentId");
                    Map<String, Object> createOrderAdjustmentContext = new HashMap<String, Object>();
                    createOrderAdjustmentContext.put("orderId", orderId);
                    createOrderAdjustmentContext.put("orderAdjustmentTypeId", "SHIPPING_CHARGES");
                    String addtlChargeDescription = shipment.getString("addtlShippingChargeDesc");
                    if (UtilValidate.isEmpty(addtlChargeDescription)) {
                        addtlChargeDescription = UtilProperties.getMessage(resource,
                                "AccountingAdditionalShippingChargeForShipment",
                                UtilMisc.toMap("shipmentId", shipmentId), locale);
                    }
                    createOrderAdjustmentContext.put("description", addtlChargeDescription);
                    createOrderAdjustmentContext.put("sourceReferenceId", shipmentId);
                    createOrderAdjustmentContext.put("amount", additionalShippingCharge);
                    createOrderAdjustmentContext.put("userLogin", context.get("userLogin"));
                    String shippingOrderAdjustmentId = null;
                    try {
                        Map<String, Object> createOrderAdjustmentResult = dispatcher
                                .runSync("createOrderAdjustment", createOrderAdjustmentContext);
                        shippingOrderAdjustmentId = (String) createOrderAdjustmentResult
                                .get("orderAdjustmentId");
                    } catch (GenericServiceException e) {
                        Debug.logError(e, "Trouble calling createOrderAdjustment service", module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingTroubleCallingCreateOrderAdjustmentService", locale));
                    }

                    // Obtain a list of OrderAdjustments due to tax on the shipping charges, if any
                    GenericValue billToParty = orh.getBillToParty();
                    GenericValue payToParty = orh.getBillFromParty();
                    GenericValue destinationContactMech = null;
                    try {
                        destinationContactMech = shipment.getRelatedOne("DestinationPostalAddress", false);
                    } catch (GenericEntityException e) {
                        Debug.logError(e,
                                "Trouble calling createInvoicesFromShipment service; invoice not created for shipment "
                                        + shipmentId,
                                module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingTroubleCallingCreateInvoicesFromShipmentService", locale));
                    }

                    List<Object> emptyList = new LinkedList<Object>();
                    Map<String, Object> calcTaxContext = new HashMap<String, Object>();
                    calcTaxContext.put("productStoreId", orh.getProductStoreId());
                    calcTaxContext.put("payToPartyId", payToParty.getString("partyId"));
                    calcTaxContext.put("billToPartyId", billToParty.getString("partyId"));
                    calcTaxContext.put("orderShippingAmount", totalAdditionalShippingCharges);
                    calcTaxContext.put("shippingAddress", destinationContactMech);

                    // These parameters don't matter if we're only worried about adjustments on the shipping charges
                    calcTaxContext.put("itemProductList", emptyList);
                    calcTaxContext.put("itemAmountList", emptyList);
                    calcTaxContext.put("itemPriceList", emptyList);
                    calcTaxContext.put("itemQuantityList", emptyList);
                    calcTaxContext.put("itemShippingList", emptyList);

                    Map<String, Object> calcTaxResult = null;
                    try {
                        calcTaxResult = dispatcher.runSync("calcTax", calcTaxContext);
                    } catch (GenericServiceException e) {
                        Debug.logError(e, "Trouble calling calcTaxService", module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingTroubleCallingCalcTaxService", locale));
                    }
                    List<GenericValue> orderAdjustments = UtilGenerics
                            .checkList(calcTaxResult.get("orderAdjustments"));

                    // If we have any OrderAdjustments due to tax on shipping, store them and add them to the total
                    if (orderAdjustments != null) {
                        for (GenericValue orderAdjustment : orderAdjustments) {
                            totalAdditionalShippingCharges = totalAdditionalShippingCharges
                                    .add(orderAdjustment.getBigDecimal("amount").setScale(DECIMALS, ROUNDING));
                            orderAdjustment.set("orderAdjustmentId", delegator.getNextSeqId("OrderAdjustment"));
                            orderAdjustment.set("orderId", orderId);
                            orderAdjustment.set("orderItemSeqId", "_NA_");
                            orderAdjustment.set("shipGroupSeqId", shipment.getString("primaryShipGroupSeqId"));
                            orderAdjustment.set("originalAdjustmentId", shippingOrderAdjustmentId);
                        }
                        try {
                            delegator.storeAll(orderAdjustments);
                        } catch (GenericEntityException e) {
                            Debug.logError(e, "Problem storing OrderAdjustments: " + orderAdjustments, module);
                            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                    "AccountingProblemStoringOrderAdjustments",
                                    UtilMisc.toMap("orderAdjustments", orderAdjustments), locale));
                        }
                    }

                    // If part of the order was paid via credit card, try to charge it for the additional shipping
                    List<GenericValue> orderPaymentPreferences = null;
                    try {
                        orderPaymentPreferences = EntityQuery.use(delegator).from("OrderPaymentPreference")
                                .where("orderId", orderId, "paymentMethodTypeId", "CREDIT_CARD").queryList();
                    } catch (GenericEntityException e) {
                        Debug.logError(e, "Problem getting OrderPaymentPreference records", module);
                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                "AccountingProblemGettingOrderPaymentPreferences", locale));
                    }

                    //  Use the first credit card we find, for the sake of simplicity
                    String paymentMethodId = null;
                    GenericValue cardOrderPaymentPref = EntityUtil.getFirst(orderPaymentPreferences);
                    if (cardOrderPaymentPref != null) {
                        paymentMethodId = cardOrderPaymentPref.getString("paymentMethodId");
                    }

                    if (paymentMethodId != null) {

                        // Release all outstanding (not settled or cancelled) authorizations, while keeping a running
                        //  total of their amounts so that the total plus the additional shipping charges can be authorized again
                        //  all at once.
                        BigDecimal totalNewAuthAmount = totalAdditionalShippingCharges.setScale(DECIMALS,
                                ROUNDING);
                        for (GenericValue orderPaymentPreference : orderPaymentPreferences) {
                            if (!(orderPaymentPreference.getString("statusId").equals("PAYMENT_SETTLED")
                                    || orderPaymentPreference.getString("statusId")
                                            .equals("PAYMENT_CANCELLED"))) {
                                GenericValue authTransaction = PaymentGatewayServices
                                        .getAuthTransaction(orderPaymentPreference);
                                if (authTransaction != null && authTransaction.get("amount") != null) {

                                    // Update the total authorized amount
                                    totalNewAuthAmount = totalNewAuthAmount.add(authTransaction
                                            .getBigDecimal("amount").setScale(DECIMALS, ROUNDING));

                                    // Release the authorization for the OrderPaymentPreference
                                    Map<String, Object> prefReleaseResult = null;
                                    try {
                                        prefReleaseResult = dispatcher.runSync("releaseOrderPaymentPreference",
                                                UtilMisc.toMap("orderPaymentPreferenceId",
                                                        orderPaymentPreference
                                                                .getString("orderPaymentPreferenceId"),
                                                        "userLogin", context.get("userLogin")));
                                    } catch (GenericServiceException e) {
                                        Debug.logError(e,
                                                "Trouble calling releaseOrderPaymentPreference service",
                                                module);
                                        return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                                "AccountingTroubleCallingReleaseOrderPaymentPreferenceService",
                                                locale));
                                    }
                                    if (ServiceUtil.isError(prefReleaseResult)
                                            || ServiceUtil.isFailure(prefReleaseResult)) {
                                        String errMsg = ServiceUtil.getErrorMessage(prefReleaseResult);
                                        Debug.logError(errMsg, module);
                                        return ServiceUtil.returnError(errMsg);
                                    }
                                }
                            }
                        }

                        // Create a new OrderPaymentPreference for the order to handle the new (totalled) charge. Don't
                        //  set the maxAmount so that it doesn't interfere with other authorizations
                        Map<String, Object> serviceContext = UtilMisc.toMap("orderId", orderId,
                                "paymentMethodId", paymentMethodId, "paymentMethodTypeId", "CREDIT_CARD",
                                "userLogin", context.get("userLogin"));
                        String orderPaymentPreferenceId = null;
                        try {
                            Map<String, Object> result = dispatcher.runSync("createOrderPaymentPreference",
                                    serviceContext);
                            orderPaymentPreferenceId = (String) result.get("orderPaymentPreferenceId");
                        } catch (GenericServiceException e) {
                            Debug.logError(e, "Trouble calling createOrderPaymentPreference service", module);
                            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                    "AccountingTroubleCallingCreateOrderPaymentPreferenceService", locale));
                        }

                        // Attempt to authorize the new orderPaymentPreference
                        Map<String, Object> authResult = null;
                        try {
                            // Use an overrideAmount because the maxAmount wasn't set on the OrderPaymentPreference
                            authResult = dispatcher.runSync("authOrderPaymentPreference",
                                    UtilMisc.toMap("orderPaymentPreferenceId", orderPaymentPreferenceId,
                                            "overrideAmount", totalNewAuthAmount, "userLogin",
                                            context.get("userLogin")));
                        } catch (GenericServiceException e) {
                            Debug.logError(e, "Trouble calling authOrderPaymentPreference service", module);
                            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                                    "AccountingTroubleCallingAuthOrderPaymentPreferenceService", locale));
                        }

                        // If the authorization fails, create the invoice anyway, but make a note of it
                        boolean authFinished = ((Boolean) authResult.get("finished")).booleanValue();
                        boolean authErrors = ((Boolean) authResult.get("errors")).booleanValue();
                        if (authErrors || !authFinished) {
                            String errMsg = UtilProperties.getMessage(resource,
                                    "AccountingUnableToAuthAdditionalShipCharges",
                                    UtilMisc.toMap("shipmentId", shipmentId, "paymentMethodId", paymentMethodId,
                                            "orderPaymentPreferenceId", orderPaymentPreferenceId),
                                    locale);
                            Debug.logError(errMsg, module);
                        }

                    }
                }
            }
        } else {
            Debug.logInfo(UtilProperties.getMessage(resource, "AccountingIgnoringAdditionalShipCharges",
                    UtilMisc.toMap("productStoreId", orh.getProductStoreId()), locale), module);
        }

        String invoiceId = null;
        GenericValue shipmentItemBilling = null;
        String shipmentId = shipmentIds.get(0);
        try {
            shipmentItemBilling = EntityQuery.use(delegator).from("ShipmentItemBilling")
                    .where("shipmentId", shipmentId).queryFirst();
        } catch (GenericEntityException e) {
            return ServiceUtil.returnError(
                    UtilProperties.getMessage(resource, "AccountingProblemGettingShipmentItemBilling", locale));
        }
        if (shipmentItemBilling != null) {
            invoiceId = shipmentItemBilling.getString("invoiceId");
        }

        // call the createInvoiceForOrder service for each order
        Map<String, Object> serviceContext = UtilMisc.toMap("orderId", orderId, "billItems", toBillItems,
                "invoiceId", invoiceId, "eventDate", context.get("eventDate"), "userLogin",
                context.get("userLogin"));
        try {
            Map<String, Object> result = dispatcher.runSync("createInvoiceForOrder", serviceContext);
            invoicesCreated.add((String) result.get("invoiceId"));
        } catch (GenericServiceException e) {
            Debug.logError(e, "Trouble calling createInvoiceForOrder service; invoice not created for shipment",
                    module);
            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                    "AccountingTroubleCallingCreateInvoiceForOrderService", locale));
        }
    }

    Map<String, Object> response = ServiceUtil.returnSuccess();
    response.put("invoicesCreated", invoicesCreated);
    return response;
}

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

/**
 * Adjusts excess penalty collection amount
 *
 * @param currentDemand//from   ww  w . ja v  a2  s .com
 * @param installments
 * @param excessPenalty
 */
private void adjustExcessPenalty(final EgDemand currentDemand, final List<Installment> installments,
        BigDecimal excessPenalty) {
    final List<EgDemandDetails> demandDetailsList = new ArrayList<>(currentDemand.getEgDemandDetails());
    final Map<Installment, Set<EgDemandDetails>> installmentWiseDemandDetails = getEgDemandDetailsSetAsMap(
            demandDetailsList, installments);
    for (final Installment installment : installments) {
        final Set<EgDemandDetails> demandDetailsSet = installmentWiseDemandDetails.get(installment);
        for (final String demandReason : DEMAND_REASONS) {
            final EgDemandDetails demandDetails = getEgDemandDetailsForReason(demandDetailsSet, demandReason);
            if (demandDetails != null) {
                final BigDecimal balance = demandDetails.getAmount().subtract(demandDetails.getAmtCollected());
                if (balance.compareTo(BigDecimal.ZERO) > 0)
                    if (excessPenalty.compareTo(BigDecimal.ZERO) > 0 && excessPenalty.compareTo(balance) <= 0) {
                        demandDetails.setAmtCollected(demandDetails.getAmtCollected().add(excessPenalty));
                        demandDetails.setModifiedDate(new Date());
                        excessPenalty = BigDecimal.ZERO;
                    } else {
                        demandDetails.setAmtCollected(demandDetails.getAmtCollected().add(balance));
                        demandDetails.setModifiedDate(new Date());
                        excessPenalty = excessPenalty.subtract(balance);
                    }
            }
            if (excessPenalty.compareTo(BigDecimal.ZERO) == 0)
                break;
        }
        if (excessPenalty.compareTo(BigDecimal.ZERO) == 0)
            break;
    }
    if (excessPenalty.compareTo(BigDecimal.ZERO) > 0) {
        final EgDemandDetails advanceDemandDetails = ptBillServiceImpl
                .insertDemandDetails(DEMANDRSN_CODE_ADVANCE, excessPenalty, currentInstall);
        currentDemand.getEgDemandDetails().add(advanceDemandDetails);
    }
}

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

/**
 * Adjusts Collection amount to installment wise demand details
 *
 * @param installments//from  w  ww.  ja va2 s  .co  m
 * @param newDemandDetailsByInstallment
 * @param demandReasons
 * @param ptDemand
 * @return
 */
private Ptdemand adjustCollection(final List<Installment> installments,
        final Map<Installment, Set<EgDemandDetails>> newDemandDetailsByInstallment,
        final Set<String> demandReasons, final Ptdemand ptDemand) {

    LOGGER.info("Entered into adjustCollection");
    EgDemandDetails advanceDemandDetails = null;
    BigDecimal balanceDemand;
    BigDecimal excessCollection = BigDecimal.ZERO;
    for (final Map<String, BigDecimal> map : excessCollAmtMap.values())
        for (final BigDecimal amount : map.values())
            excessCollection = excessCollection.add(amount);
    final Installment currSecondHalf = propertyTaxUtil.getInstallmentsForCurrYear(new Date())
            .get(PropertyTaxConstants.CURRENTYEAR_SECOND_HALF);
    if (excessCollection.compareTo(BigDecimal.ZERO) > 0) {
        BigDecimal collection = BigDecimal.ZERO;
        for (final EgDemandDetails demandDetials : ptDemand.getEgDemandDetails()) {
            if (advanceDemandDetails == null
                    && DEMANDRSN_CODE_ADVANCE
                            .equals(demandDetials.getEgDemandReason().getEgDemandReasonMaster().getCode())
                    && currSecondHalf.equals(demandDetials.getEgDemandReason().getEgInstallmentMaster()))
                advanceDemandDetails = demandDetials;
            if (!demandDetials.getEgDemandReason().getEgDemandReasonMaster().getCode()
                    .equalsIgnoreCase(DEMANDRSN_CODE_PENALTY_FINES)) {
                collection = collection.add(demandDetials.getAmtCollected());
                demandDetials.setAmtCollected(BigDecimal.ZERO);
            }
        }
        collection = collection.add(excessCollection);
        for (final Installment installment : installments) {
            for (final String demandReason : demandReasons) {
                final EgDemandDetails newDemandDetail = getEgDemandDetailsForReason(
                        newDemandDetailsByInstallment.get(installment), demandReason);

                if (newDemandDetail != null) {
                    balanceDemand = newDemandDetail.getAmount().subtract(newDemandDetail.getAmtCollected());

                    if (balanceDemand.compareTo(BigDecimal.ZERO) > 0
                            && collection.compareTo(BigDecimal.ZERO) > 0)
                        if (collection.compareTo(balanceDemand) <= 0) {
                            newDemandDetail.setAmtCollected(newDemandDetail.getAmtCollected().add(collection));
                            newDemandDetail.setModifiedDate(new Date());
                            collection = BigDecimal.ZERO;
                        } else {
                            newDemandDetail
                                    .setAmtCollected(newDemandDetail.getAmtCollected().add(balanceDemand));
                            newDemandDetail.setModifiedDate(new Date());
                            collection = collection.subtract(balanceDemand);
                        }
                }
                if (collection.compareTo(BigDecimal.ZERO) == 0)
                    break;
            }
            if (collection.compareTo(BigDecimal.ZERO) == 0)
                break;
        }

        if (collection.compareTo(BigDecimal.ZERO) > 0)
            if (advanceDemandDetails == null) {
                final EgDemandDetails demandDetails = ptBillServiceImpl
                        .insertDemandDetails(DEMANDRSN_CODE_ADVANCE, collection, currSecondHalf);
                ptDemand.getEgDemandDetails().add(demandDetails);
            } else
                advanceDemandDetails.getAmtCollected().add(collection);
        LOGGER.info("Exiting from adjustCollection");

    }
    return ptDemand;
}

From source file:org.egov.egf.commons.EgovCommon.java

public BigDecimal getAccCodeBalanceForIndirectExpense(final Date asondate, final String glcode,
        final Integer accountdetailType, final String accountdetailkey) throws ValidationException, Exception {
    LOGGER.debug("EgovCommon | getAccCodeBalanceForIndirectExpense | Start");
    validateParameterData(asondate, glcode, accountdetailType, accountdetailkey);
    final StringBuffer glCodeBalQry = new StringBuffer(400);
    final StringBuffer glCodeDbtBalQry = new StringBuffer(400);
    final StringBuffer glCodeCrdBalQry = new StringBuffer(400);
    BigDecimal glCodeBalance = BigDecimal.ZERO;
    BigDecimal subledgerDbtBalance = BigDecimal.ZERO;
    BigDecimal subledgerCrdBalance = BigDecimal.ZERO;

    final List<AppConfigValues> appList = appConfigValuesService
            .getConfigValuesByModuleAndKey(FinancialConstants.MODULE_NAME_APPCONFIG, "statusexcludeReport");
    final String statusExclude = appList.get(0).getValue();
    if (null == accountdetailType && null == accountdetailkey) {
        glCodeBalQry.append(//w w  w . j a  v  a 2s  .  c  om
                "SELECT (case when sum(gl.debitAmount)=null then 0 else sum(gl.debitAmount) end - case when sum(gl.creditAmount)  = null then 0 else sum(gl.creditAmount) end)")
                .append(" as amount FROM  CGeneralLedger gl , CVoucherHeader vh WHERE  gl.voucherHeaderId.id=vh.id and gl.glcodeId.glcode=?")
                .append(" and vh.voucherDate >= (select startingDate from CFinancialYear where  startingDate <= '")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("' AND endingDate >='")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("') and vh.voucherDate <='")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("'and vh.status not in (")
                .append(statusExclude)
                .append(") and ((vh.name='Contractor Journal' and state_id is null) or(vh.name !='Contractor Journal' and vh.name !='CapitalisedAsset' ) )");

        final List<Object> list = getPersistenceService().findAllBy(glCodeBalQry.toString(), glcode);
        glCodeBalance = BigDecimal.valueOf((Double) list.get(0));
    } else {
        // Getting the debit balance.
        glCodeDbtBalQry.append(
                "SELECT sum(gld.amount)  as debitamount from CVoucherHeader vh , CGeneralLedger gl,CGeneralLedgerDetail gld")
                .append(" WHERE gl.voucherHeaderId.id=vh.id and gl.id = gld.generalLedgerId.id and gl.glcodeId.glcode=?  ")
                .append(" and vh.voucherDate >= (select startingDate from CFinancialYear where  startingDate <= '")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("' AND endingDate >='")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("') and vh.voucherDate <='")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("'and vh.status not in (")
                .append(statusExclude)
                .append(")and ((vh.name='Contractor Journal' and state_id is null) or(vh.name !='Contractor Journal' and vh.name !='CapitalisedAsset') ) ")
                .append(" and gld.detailTypeId.id =").append(accountdetailType);
        if (null != accountdetailkey)
            glCodeDbtBalQry.append(" and gld.detailKeyId in (").append(accountdetailkey).append(")");
        glCodeDbtBalQry.append(" and gl.debitAmount >0");
        final List<Object> listDbt = getPersistenceService().findAllBy(glCodeDbtBalQry.toString(), glcode);
        subledgerDbtBalance = (BigDecimal) listDbt.get(0) == null ? BigDecimal.ZERO
                : (BigDecimal) listDbt.get(0);
        if (LOGGER.isDebugEnabled())
            LOGGER.debug(" total debit amount :  " + subledgerDbtBalance);

        // get the credit balance

        glCodeCrdBalQry.append(
                "SELECT sum(gld.amount) as creditamount from CVoucherHeader vh , CGeneralLedger gl,CGeneralLedgerDetail gld")
                .append(" WHERE gl.voucherHeaderId.id=vh.id and gl.id = gld.generalLedgerId.id and gl.glcodeId.glcode=?  ")
                .append(" and vh.voucherDate >= (select startingDate from CFinancialYear where  startingDate <= '")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("' AND endingDate >='")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("') and vh.voucherDate <='")
                .append(Constants.DDMMYYYYFORMAT1.format(asondate)).append("'and vh.status not in (")
                .append(statusExclude)
                .append(")and ((vh.name='Contractor Journal' and state_id is null) or(vh.name !='Contractor Journal' and vh.name !='CapitalisedAsset' ) )")
                .append(" and gld.detailTypeId.id =").append(accountdetailType);
        if (null != accountdetailkey)
            glCodeCrdBalQry.append(" and gld.detailKeyId in(").append(accountdetailkey).append(")");
        glCodeCrdBalQry.append(" and gl.creditAmount >0");
        final List<Object> listCrd = getPersistenceService().findAllBy(glCodeCrdBalQry.toString(), glcode);
        subledgerCrdBalance = (BigDecimal) listCrd.get(0) == null ? BigDecimal.ZERO
                : (BigDecimal) listCrd.get(0);
        if (LOGGER.isDebugEnabled())
            LOGGER.debug(" total credit amount :  " + subledgerCrdBalance);
        glCodeBalance = subledgerDbtBalance.subtract(subledgerCrdBalance);
        if (LOGGER.isDebugEnabled())
            LOGGER.debug(" total balance amount :  " + glCodeBalance);

    }
    if (LOGGER.isDebugEnabled())
        LOGGER.debug("EgovCommon | getAccCodeBalanceForIndirectExpense | End");
    glCodeBalance = glCodeBalance.setScale(2);
    return glCodeBalance;
}

From source file:com.aoindustries.website.signup.SignupCustomizeServerActionHelper.java

public static void setRequestAttributes(ServletContext servletContext, HttpServletRequest request,
        HttpServletResponse response, SignupSelectPackageForm signupSelectPackageForm,
        SignupCustomizeServerForm signupCustomizeServerForm) throws IOException, SQLException {
    AOServConnector rootConn = SiteSettings.getInstance(servletContext).getRootAOServConnector();
    PackageDefinition packageDefinition = rootConn.getPackageDefinitions()
            .get(signupSelectPackageForm.getPackageDefinition());
    if (packageDefinition == null)
        throw new SQLException(
                "Unable to find PackageDefinition: " + signupSelectPackageForm.getPackageDefinition());
    List<PackageDefinitionLimit> limits = packageDefinition.getLimits();

    // Find the cheapest resources to scale prices from
    int maxPowers = 0;
    PackageDefinitionLimit cheapestPower = null;
    int maxCPUs = 0;
    PackageDefinitionLimit cheapestCPU = null;
    int maxRAMs = 0;
    PackageDefinitionLimit cheapestRAM = null;
    int maxSataControllers = 0;
    PackageDefinitionLimit cheapestSataController = null;
    int maxScsiControllers = 0;
    PackageDefinitionLimit cheapestScsiController = null;
    int maxDisks = 0;
    PackageDefinitionLimit cheapestDisk = null;
    for (PackageDefinitionLimit limit : limits) {
        String resourceName = limit.getResource().getName();
        if (resourceName.startsWith("hardware_power_")) {
            int limitPower = limit.getHardLimit();
            if (limitPower > 0) {
                if (limitPower > maxPowers)
                    maxPowers = limitPower;
                if (cheapestPower == null)
                    cheapestPower = limit;
                else {
                    BigDecimal additionalRate = limit.getAdditionalRate();
                    if (additionalRate == null)
                        additionalRate = BigDecimal.valueOf(0, 2);
                    BigDecimal cheapestRate = cheapestPower.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    if (additionalRate.compareTo(cheapestRate) < 0)
                        cheapestPower = limit;
                }//from   w  w  w. j a v a2 s. co  m
            }
        } else if (resourceName.startsWith("hardware_processor_")) {
            int limitCpu = limit.getHardLimit();
            if (limitCpu > 0) {
                if (limitCpu > maxCPUs)
                    maxCPUs = limitCpu;
                if (cheapestCPU == null)
                    cheapestCPU = limit;
                else {
                    BigDecimal additionalRate = limit.getAdditionalRate();
                    if (additionalRate == null)
                        additionalRate = BigDecimal.valueOf(0, 2);
                    BigDecimal cheapestRate = cheapestCPU.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    if (additionalRate.compareTo(cheapestRate) < 0)
                        cheapestCPU = limit;
                }
            }
        } else if (resourceName.startsWith("hardware_ram_")) {
            int limitRAM = limit.getHardLimit();
            if (limitRAM > 0) {
                if (limitRAM > maxRAMs)
                    maxRAMs = limitRAM;
                if (cheapestRAM == null)
                    cheapestRAM = limit;
                else {
                    BigDecimal additionalRate = limit.getAdditionalRate();
                    if (additionalRate == null)
                        additionalRate = BigDecimal.valueOf(0, 2);
                    BigDecimal cheapestRate = cheapestRAM.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    if (additionalRate.compareTo(cheapestRate) < 0)
                        cheapestRAM = limit;
                }
            }
        } else if (resourceName.startsWith("hardware_disk_controller_sata_")) {
            int limitSataController = limit.getHardLimit();
            if (limitSataController > 0) {
                if (limitSataController > maxSataControllers)
                    maxSataControllers = limitSataController;
                if (cheapestSataController == null)
                    cheapestSataController = limit;
                else {
                    BigDecimal additionalRate = limit.getAdditionalRate();
                    if (additionalRate == null)
                        additionalRate = BigDecimal.valueOf(0, 2);
                    BigDecimal cheapestRate = cheapestSataController.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    if (additionalRate.compareTo(cheapestRate) < 0)
                        cheapestSataController = limit;
                }
            }
        } else if (resourceName.startsWith("hardware_disk_controller_scsi_")) {
            int limitScsiController = limit.getHardLimit();
            if (limitScsiController > 0) {
                if (limitScsiController > maxScsiControllers)
                    maxScsiControllers = limitScsiController;
                if (cheapestScsiController == null)
                    cheapestScsiController = limit;
                else {
                    BigDecimal additionalRate = limit.getAdditionalRate();
                    if (additionalRate == null)
                        additionalRate = BigDecimal.valueOf(0, 2);
                    BigDecimal cheapestRate = cheapestScsiController.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    if (additionalRate.compareTo(cheapestRate) < 0)
                        cheapestScsiController = limit;
                }
            }
        } else if (resourceName.startsWith("hardware_disk_")) {
            int hardLimit = limit.getHardLimit();
            if (hardLimit > 0) {
                if (cheapestDisk == null)
                    cheapestDisk = limit;
                else {
                    BigDecimal additionalRate = limit.getAdditionalRate();
                    if (additionalRate == null)
                        additionalRate = BigDecimal.valueOf(0, 2);
                    BigDecimal cheapestRate = cheapestDisk.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    if (additionalRate.compareTo(cheapestRate) < 0)
                        cheapestDisk = limit;
                }
                if (hardLimit > maxDisks)
                    maxDisks = hardLimit;
            }
        }
    }
    if (cheapestCPU == null)
        throw new SQLException("Unable to find cheapestCPU");
    if (cheapestRAM == null)
        throw new SQLException("Unable to find cheapestRAM");
    if (cheapestDisk == null)
        throw new SQLException("Unable to find cheapestDisk");

    // Find all the options
    List<Option> powerOptions = new ArrayList<Option>();
    List<Option> cpuOptions = new ArrayList<Option>();
    List<Option> ramOptions = new ArrayList<Option>();
    List<Option> sataControllerOptions = new ArrayList<Option>();
    List<Option> scsiControllerOptions = new ArrayList<Option>();
    List<List<Option>> diskOptions = new ArrayList<List<Option>>();
    for (int c = 0; c < maxDisks; c++)
        diskOptions.add(new ArrayList<Option>());
    for (PackageDefinitionLimit limit : limits) {
        Resource resource = limit.getResource();
        String resourceName = resource.getName();
        if (resourceName.startsWith("hardware_power_")) {
            int limitPower = limit.getHardLimit();
            if (limitPower > 0) {
                assert cheapestPower != null;
                BigDecimal additionalRate = limit.getAdditionalRate();
                if (additionalRate == null)
                    additionalRate = BigDecimal.valueOf(0, 2);
                BigDecimal cheapestRate = cheapestPower.getAdditionalRate();
                if (cheapestRate == null)
                    cheapestRate = BigDecimal.valueOf(0, 2);
                String description = maxPowers == 1 ? resource.toString()
                        : (maxPowers + "x" + resource.toString());
                powerOptions.add(new Option(limit.getPkey(), description,
                        BigDecimal.valueOf(maxPowers).multiply(additionalRate.subtract(cheapestRate))));
            }
        } else if (resourceName.startsWith("hardware_processor_")) {
            int limitCpu = limit.getHardLimit();
            if (limitCpu > 0) {
                BigDecimal additionalRate = limit.getAdditionalRate();
                if (additionalRate == null)
                    additionalRate = BigDecimal.valueOf(0, 2);
                BigDecimal cheapestRate = cheapestCPU.getAdditionalRate();
                if (cheapestRate == null)
                    cheapestRate = BigDecimal.valueOf(0, 2);
                String description = maxCPUs == 1 ? resource.toString() : (maxCPUs + "x" + resource.toString());
                cpuOptions.add(new Option(limit.getPkey(), description,
                        BigDecimal.valueOf(maxCPUs).multiply(additionalRate.subtract(cheapestRate))));
            }
        } else if (resourceName.startsWith("hardware_ram_")) {
            int limitRAM = limit.getHardLimit();
            if (limitRAM > 0) {
                BigDecimal additionalRate = limit.getAdditionalRate();
                if (additionalRate == null)
                    additionalRate = BigDecimal.valueOf(0, 2);
                BigDecimal cheapestRate = cheapestRAM.getAdditionalRate();
                if (cheapestRate == null)
                    cheapestRate = BigDecimal.valueOf(0, 2);
                String description = maxRAMs == 1 ? resource.toString() : (maxRAMs + "x" + resource.toString());
                ramOptions.add(new Option(limit.getPkey(), description,
                        BigDecimal.valueOf(maxRAMs).multiply(additionalRate.subtract(cheapestRate))));
            }
        } else if (resourceName.startsWith("hardware_disk_controller_sata_")) {
            int limitSataController = limit.getHardLimit();
            if (limitSataController > 0) {
                assert cheapestSataController != null;
                BigDecimal additionalRate = limit.getAdditionalRate();
                if (additionalRate == null)
                    additionalRate = BigDecimal.valueOf(0, 2);
                BigDecimal cheapestRate = cheapestSataController.getAdditionalRate();
                if (cheapestRate == null)
                    cheapestRate = BigDecimal.valueOf(0, 2);
                String description = maxSataControllers == 1 ? resource.toString()
                        : (maxSataControllers + "x" + resource.toString());
                sataControllerOptions.add(new Option(limit.getPkey(), description, BigDecimal
                        .valueOf(maxSataControllers).multiply(additionalRate.subtract(cheapestRate))));
            }
        } else if (resourceName.startsWith("hardware_disk_controller_scsi_")) {
            int limitScsiController = limit.getHardLimit();
            if (limitScsiController > 0) {
                assert cheapestScsiController != null;
                BigDecimal additionalRate = limit.getAdditionalRate();
                if (additionalRate == null)
                    additionalRate = BigDecimal.valueOf(0, 2);
                BigDecimal cheapestRate = cheapestScsiController.getAdditionalRate();
                if (cheapestRate == null)
                    cheapestRate = BigDecimal.valueOf(0, 2);
                String description = maxScsiControllers == 1 ? resource.toString()
                        : (maxScsiControllers + "x" + resource.toString());
                scsiControllerOptions.add(new Option(limit.getPkey(), description, BigDecimal
                        .valueOf(maxScsiControllers).multiply(additionalRate.subtract(cheapestRate))));
            }
        } else if (resourceName.startsWith("hardware_disk_")) {
            int limitDisk = limit.getHardLimit();
            if (limitDisk > 0) {
                BigDecimal additionalRate = limit.getAdditionalRate();
                if (additionalRate == null)
                    additionalRate = BigDecimal.valueOf(0, 2);
                BigDecimal adjustedRate = additionalRate;
                // Discount adjusted rate if the cheapest disk is of this type
                if (cheapestDisk.getResource().getName().startsWith("hardware_disk_")) {
                    BigDecimal cheapestRate = cheapestDisk.getAdditionalRate();
                    if (cheapestRate == null)
                        cheapestRate = BigDecimal.valueOf(0, 2);
                    adjustedRate = adjustedRate.subtract(cheapestRate);
                }
                for (int c = 0; c < maxDisks; c++) {
                    List<Option> options = diskOptions.get(c);
                    // Add none option
                    if (maxDisks > 1 && options.isEmpty())
                        options.add(new Option(-1, "None",
                                c == 0 ? adjustedRate.subtract(additionalRate) : BigDecimal.valueOf(0, 2)));
                    options.add(new Option(limit.getPkey(), resource.toString(),
                            c == 0 ? adjustedRate : additionalRate));
                }
            }
        }
    }

    // Sort by price
    Collections.sort(powerOptions, new Option.PriceComparator());
    Collections.sort(cpuOptions, new Option.PriceComparator());
    Collections.sort(ramOptions, new Option.PriceComparator());
    Collections.sort(sataControllerOptions, new Option.PriceComparator());
    Collections.sort(scsiControllerOptions, new Option.PriceComparator());
    for (List<Option> diskOptionList : diskOptions)
        Collections.sort(diskOptionList, new Option.PriceComparator());

    // Clear any customization settings that are not part of the current package definition (this happens when they
    // select a different package type)
    if (signupCustomizeServerForm.getPowerOption() != -1) {
        PackageDefinitionLimit pdl = rootConn.getPackageDefinitionLimits()
                .get(signupCustomizeServerForm.getPowerOption());
        if (pdl == null || !packageDefinition.equals(pdl.getPackageDefinition()))
            signupCustomizeServerForm.setPowerOption(-1);
    }
    if (signupCustomizeServerForm.getCpuOption() != -1) {
        PackageDefinitionLimit pdl = rootConn.getPackageDefinitionLimits()
                .get(signupCustomizeServerForm.getCpuOption());
        if (pdl == null || !packageDefinition.equals(pdl.getPackageDefinition()))
            signupCustomizeServerForm.setCpuOption(-1);
    }
    if (signupCustomizeServerForm.getRamOption() != -1) {
        PackageDefinitionLimit pdl = rootConn.getPackageDefinitionLimits()
                .get(signupCustomizeServerForm.getRamOption());
        if (pdl == null || !packageDefinition.equals(pdl.getPackageDefinition()))
            signupCustomizeServerForm.setRamOption(-1);
    }
    if (signupCustomizeServerForm.getSataControllerOption() != -1) {
        PackageDefinitionLimit pdl = rootConn.getPackageDefinitionLimits()
                .get(signupCustomizeServerForm.getSataControllerOption());
        if (pdl == null || !packageDefinition.equals(pdl.getPackageDefinition()))
            signupCustomizeServerForm.setSataControllerOption(-1);
    }
    if (signupCustomizeServerForm.getScsiControllerOption() != -1) {
        PackageDefinitionLimit pdl = rootConn.getPackageDefinitionLimits()
                .get(signupCustomizeServerForm.getScsiControllerOption());
        if (pdl == null || !packageDefinition.equals(pdl.getPackageDefinition()))
            signupCustomizeServerForm.setScsiControllerOption(-1);
    }
    List<String> formDiskOptions = signupCustomizeServerForm.getDiskOptions();
    while (formDiskOptions.size() > maxDisks)
        formDiskOptions.remove(formDiskOptions.size() - 1);
    for (int c = 0; c < formDiskOptions.size(); c++) {
        String S = formDiskOptions.get(c);
        if (S != null && S.length() > 0 && !S.equals("-1")) {
            int pkey = Integer.parseInt(S);
            PackageDefinitionLimit pdl = rootConn.getPackageDefinitionLimits().get(pkey);
            if (pdl == null || !packageDefinition.equals(pdl.getPackageDefinition()))
                formDiskOptions.set(c, "-1");
        }
    }

    // Determine if at least one disk is selected
    boolean isAtLeastOneDiskSelected = signupCustomizeServerForm.isAtLeastOneDiskSelected();

    // Default to cheapest if not already selected
    if (cheapestPower != null && signupCustomizeServerForm.getPowerOption() == -1)
        signupCustomizeServerForm.setPowerOption(cheapestPower.getPkey());
    if (signupCustomizeServerForm.getCpuOption() == -1)
        signupCustomizeServerForm.setCpuOption(cheapestCPU.getPkey());
    if (signupCustomizeServerForm.getRamOption() == -1)
        signupCustomizeServerForm.setRamOption(cheapestRAM.getPkey());
    if (cheapestSataController != null && signupCustomizeServerForm.getSataControllerOption() == -1)
        signupCustomizeServerForm.setSataControllerOption(cheapestSataController.getPkey());
    if (cheapestScsiController != null && signupCustomizeServerForm.getScsiControllerOption() == -1)
        signupCustomizeServerForm.setScsiControllerOption(cheapestScsiController.getPkey());
    for (int c = 0; c < maxDisks; c++) {
        List<Option> options = diskOptions.get(c);
        if (!options.isEmpty()) {
            Option firstOption = options.get(0);
            if (!isAtLeastOneDiskSelected && options.size() >= 2
                    && firstOption.getPriceDifference().compareTo(BigDecimal.ZERO) < 0) {
                firstOption = options.get(1);
            }
            String defaultSelected = Integer.toString(firstOption.getPackageDefinitionLimit());
            if (formDiskOptions.size() <= c || formDiskOptions.get(c) == null
                    || formDiskOptions.get(c).length() == 0 || formDiskOptions.get(c).equals("-1"))
                formDiskOptions.set(c, defaultSelected);
        } else {
            formDiskOptions.set(c, "-1");
        }
    }

    // Find the basePrice (base plus minimum number of cheapest of each resource class)
    BigDecimal basePrice = packageDefinition.getMonthlyRate();
    if (basePrice == null)
        basePrice = BigDecimal.valueOf(0, 2);
    if (cheapestPower != null && cheapestPower.getAdditionalRate() != null)
        basePrice = basePrice.add(cheapestPower.getAdditionalRate().multiply(BigDecimal.valueOf(maxPowers)));
    if (cheapestCPU.getAdditionalRate() != null)
        basePrice = basePrice.add(cheapestCPU.getAdditionalRate().multiply(BigDecimal.valueOf(maxCPUs)));
    if (cheapestRAM.getAdditionalRate() != null)
        basePrice = basePrice.add(cheapestRAM.getAdditionalRate());
    if (cheapestSataController != null && cheapestSataController.getAdditionalRate() != null)
        basePrice = basePrice.add(cheapestSataController.getAdditionalRate());
    if (cheapestScsiController != null && cheapestScsiController.getAdditionalRate() != null)
        basePrice = basePrice.add(cheapestScsiController.getAdditionalRate());
    if (cheapestDisk.getAdditionalRate() != null)
        basePrice = basePrice.add(cheapestDisk.getAdditionalRate());

    // Store to request
    request.setAttribute("packageDefinition", packageDefinition);
    request.setAttribute("powerOptions", powerOptions);
    request.setAttribute("cpuOptions", cpuOptions);
    request.setAttribute("ramOptions", ramOptions);
    request.setAttribute("sataControllerOptions", sataControllerOptions);
    request.setAttribute("scsiControllerOptions", scsiControllerOptions);
    request.setAttribute("diskOptions", diskOptions);
    request.setAttribute("basePrice", basePrice);
}