svn commit: r543923 - in /ofbiz/trunk/applications: accounting/servicedef/ accounting/src/org/ofbiz/accounting/payment/ accounting/widget/ order/src/org/ofbiz/order/shoppingcart/ order/webapp/ordermgr/entry/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r543923 - in /ofbiz/trunk/applications: accounting/servicedef/ accounting/src/org/ofbiz/accounting/payment/ accounting/widget/ order/src/org/ofbiz/order/shoppingcart/ order/webapp/ordermgr/entry/

jacopoc
Author: jacopoc
Date: Sun Jun  3 09:06:37 2007
New Revision: 543923

URL: http://svn.apache.org/viewvc?view=rev&rev=543923
Log:
First version of the billing accounts' process refactoring effort: now most of the more critical bugs that were affecting the billing accounts are fixed (OFBIZ-901). There is still some work to do to consolidate and cleanup older code, and an issue with approximations under certain conditions (that is my next task).
The most remarkable difference from the existing code (that was an incomplete implementation of the processes needed to effectively use billing accounts) is that now payment applications are *not* applied to a billing account; they are simply associated to it and can be applied to pay the invoices associated to the billing account.

Modified:
    ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml
    ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/BillingAccountWorker.java
    ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java
    ofbiz/trunk/applications/accounting/widget/BillingAccountForms.xml
    ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java
    ofbiz/trunk/applications/order/webapp/ordermgr/entry/billsettings.ftl

Modified: ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml?view=diff&rev=543923&r1=543922&r2=543923
==============================================================================
--- ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml (original)
+++ ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml Sun Jun  3 09:06:37 2007
@@ -275,6 +275,7 @@
         <attribute name="processResult" type="String" mode="OUT" optional="false"/>
     </service>
 
+    <!-- deprecated in favour of captureBillingAccountPayments -->
     <service name="captureBillingAccountPayment" engine="java"
             location="org.ofbiz.accounting.payment.PaymentGatewayServices" invoke="captureBillingAccountPayment" auth="true">
         <description>Records a settlement or payment of an invoice by a billing account for the given captureAmount</description>
@@ -284,6 +285,14 @@
         <attribute name="orderId" type="String" mode="IN" optional="true"/>
         <attribute name="paymentId" type="String" mode="OUT" optional="false"/>
         <attribute name="paymentGatewayResponseId" type="String" mode="OUT" optional="true"/>
+    </service>
+    <service name="captureBillingAccountPayments" engine="java"
+            location="org.ofbiz.accounting.payment.PaymentGatewayServices" invoke="captureBillingAccountPayments" auth="true">
+        <description>Applies (part of) the unapplied payment applications associated to the billing account to the given invoice.</description>
+        <attribute name="billingAccountId" type="String" mode="IN" optional="false"/>
+        <attribute name="invoiceId" type="String" mode="IN" optional="false"/>
+        <attribute name="captureAmount" type="Double" mode="INOUT" optional="false"/>
+        <attribute name="orderId" type="String" mode="IN" optional="true"/>
     </service>
 
     <service name="processCaptureSplitPayment" engine="java" require-new-transaction="true"

Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/BillingAccountWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/BillingAccountWorker.java?view=diff&rev=543923&r1=543922&r2=543923
==============================================================================
--- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/BillingAccountWorker.java (original)
+++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/BillingAccountWorker.java Sun Jun  3 09:06:37 2007
@@ -32,6 +32,7 @@
 import org.ofbiz.base.util.UtilDateTime;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilNumber;
+import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
@@ -123,15 +124,59 @@
     }
     
     /**
-     * Calculates the "available" balance of a billing account, which is net balance minus amount of pending (not canceled, rejected, or completed) orders.  
-     * Available balance will not exceed billing account's accountLimit.  
-     * When looking at using a billing account for a new order, you should use this method.  
-     * @param delegator
+     * Calculates the "available" balance of a billing account, which is the
+     * net balance minus amount of pending (not cancelled, rejected, or received) order payments.  
+     * When looking at using a billing account for a new order, you should use this method.
      * @param billingAccountId
+     * @param delegator
      * @return
      * @throws GenericEntityException
      */
+    public static BigDecimal getBillingAccountBalance(GenericDelegator delegator, String billingAccountId) throws GenericEntityException {
+        GenericValue billingAccount = delegator.findByPrimaryKey("BillingAccount", UtilMisc.toMap("billingAccountId", billingAccountId));
+        return getBillingAccountBalance(billingAccount);
+    }
+
     public static BigDecimal getBillingAccountBalance(GenericValue billingAccount) throws GenericEntityException {
+        
+        GenericDelegator delegator = billingAccount.getDelegator();
+        String billingAccountId = billingAccount.getString("billingAccountId");
+
+        BigDecimal balance = ZERO;
+        BigDecimal accountLimit = getAccountLimit(billingAccount);
+        balance = balance.add(accountLimit);
+        // pending (not cancelled, rejected, or received) order payments
+        EntityConditionList whereConditions = new EntityConditionList(UtilMisc.toList(
+                new EntityExpr("billingAccountId", EntityOperator.EQUALS, billingAccountId),
+                new EntityExpr("paymentMethodTypeId", EntityOperator.EQUALS, "EXT_BILLACT"),
+                new EntityExpr("statusId", EntityOperator.NOT_IN, UtilMisc.toList("ORDER_CANCELLED", "ORDER_REJECTED")),
+                new EntityExpr("preferenceStatusId", EntityOperator.NOT_IN, UtilMisc.toList("PAYMENT_SETTLED", "PAYMENT_RECEIVED", "PAYMENT_DECLINED", "PAYMENT_CANCELLED")) // PAYMENT_NOT_AUTH
+            ), EntityOperator.AND);
+
+        GenericValue orderPaymentPreferenceSum = EntityUtil.getFirst(delegator.findByCondition("OrderPurchasePaymentSummary", whereConditions, null, UtilMisc.toList("maxAmount"), null, null));
+        BigDecimal ordersTotal = null;
+        if (UtilValidate.isNotEmpty(orderPaymentPreferenceSum)) {
+            ordersTotal = orderPaymentPreferenceSum.getBigDecimal("maxAmount");
+        } else {
+            ordersTotal = ZERO;
+        }
+        balance = balance.subtract(ordersTotal);
+
+        List paymentAppls = delegator.findByAnd("PaymentApplication", UtilMisc.toMap("billingAccountId", billingAccountId));
+        // TODO: cancelled payments?
+        if (paymentAppls != null) {
+            for (Iterator pAi = paymentAppls.iterator(); pAi.hasNext(); ) {
+                GenericValue paymentAppl = (GenericValue) pAi.next();
+                if (paymentAppl.getString("invoiceId") == null) {
+                    BigDecimal amountApplied = paymentAppl.getBigDecimal("amountApplied");
+                    balance = balance.add(amountApplied);
+                }
+            }
+        }
+    
+        balance = balance.setScale(decimals, rounding);
+        return balance;
+        /*
         GenericDelegator delegator = billingAccount.getDelegator();
         String billingAccountId = billingAccount.getString("billingAccountId");
         
@@ -160,6 +205,7 @@
             balance = balance.setScale(decimals, rounding);    
         }
         return balance;
+         */
     }
     
     /**
@@ -172,11 +218,6 @@
                     new EntityExpr("statusId", EntityOperator.NOT_EQUAL, "ORDER_CANCELLED"),
                     new EntityExpr("statusId", EntityOperator.NOT_EQUAL, "ORDER_COMPLETED")));
     }
-    
-    public static BigDecimal getBillingAccountBalance(GenericDelegator delegator, String billingAccountId) throws GenericEntityException {
-        GenericValue billingAccount = delegator.findByPrimaryKey("BillingAccount", UtilMisc.toMap("billingAccountId", billingAccountId));
-        return getBillingAccountBalance(billingAccount);
-    }
     
     /**
      * Returns the amount which could be charged to a billing account, which is defined as the accountLimit minus account balance and minus the balance of outstanding orders

Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java?view=diff&rev=543923&r1=543922&r2=543923
==============================================================================
--- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java (original)
+++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java Sun Jun  3 09:06:37 2007
@@ -34,6 +34,7 @@
 import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.GenericDelegator;
+import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
 import org.ofbiz.entity.condition.EntityCondition;
@@ -968,7 +969,7 @@
         }
 
         // get the invoice amount (amount to bill)
-        double invoiceTotal = InvoiceWorker.getInvoiceTotal(invoice);
+        double invoiceTotal = InvoiceWorker.getInvoiceNotApplied(invoice).doubleValue();
         if (Debug.infoOn()) Debug.logInfo("(Capture) Invoice [#" + invoiceId + "] total: " + invoiceTotal, module);
 
         // now capture the order
@@ -1001,6 +1002,7 @@
         // get the order header and payment preferences
         GenericValue orderHeader = null;
         List paymentPrefs = null;
+        List paymentPrefsBa = null;
 
         try {
             orderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId));
@@ -1009,6 +1011,11 @@
             Map lookupMap = UtilMisc.toMap("orderId", orderId, "statusId", "PAYMENT_AUTHORIZED");
             List orderList = UtilMisc.toList("-maxAmount");
             paymentPrefs = delegator.findByAnd("OrderPaymentPreference", lookupMap, orderList);
+
+            if (UtilValidate.isNotEmpty(billingAccountId)) {
+                lookupMap = UtilMisc.toMap("orderId", orderId, "paymentMethodTypeId", "EXT_BILLACT", "statusId", "PAYMENT_NOT_RECEIVED");
+                paymentPrefsBa = delegator.findByAnd("OrderPaymentPreference", lookupMap, orderList);
+            }
         } catch (GenericEntityException gee) {
             Debug.logError(gee, "Problems getting entity record(s), see stack trace", module);
             return ServiceUtil.returnError("ERROR: Could not get order information (" + gee.toString() + ").");
@@ -1032,71 +1039,95 @@
         amountToCapture = amountToCapture.min(remainingTotalBd);
         if (Debug.infoOn()) Debug.logInfo("Actual Expected Capture Amount : " + amountToCapture, module);
 
-        // See if there is a billing account first.  If so, just charge the captureAmount to the billing account via PaymentApplication
-        GenericValue billingAccount = null;
-        BigDecimal billingAccountAvail = null;
-        BigDecimal billingAccountCaptureAmount = ZERO;
-        Map billingAccountInfo = null;
-        if (UtilValidate.isNotEmpty(billingAccountId)) {
-            try {
-                billingAccountInfo = dispatcher.runSync("calcBillingAccountBalance", UtilMisc.toMap("billingAccountId", billingAccountId));
-            } catch (GenericServiceException e) {
-                Debug.logError(e, "Unable to get billing account information for #" + billingAccountId, module);
-            }
-        }
-        if (billingAccountInfo != null) {
-            billingAccount = (GenericValue) billingAccountInfo.get("billingAccount");
-            // use available to capture because we want to know how much we can charge to a billing account
-            Double availableToCapture = (Double) billingAccountInfo.get("availableToCapture");  
-            billingAccountAvail = new BigDecimal(availableToCapture.doubleValue());
-        }
-        
-        // if a billing account is used to pay for an order, then charge as much as we can to it before proceeding to other payment methods.
-        if (billingAccount != null && billingAccountAvail != null) {
-            try {
-                // the amount to be "charged" to the billing account, which is the minimum of the amount the order wants to charge to the billing account
-                // or the amount still available for capturing from the billing account or the total amount to be captured on the order
-                BigDecimal billingAccountMaxAmount = new BigDecimal(orh.getBillingAccountMaxAmount());
-                billingAccountCaptureAmount = billingAccountMaxAmount.min(billingAccountAvail).min(amountToCapture);
-                Debug.logInfo("billing account avail = [" + billingAccountAvail + "] capture amount = [" + billingAccountCaptureAmount + "] maxAmount = ["+billingAccountMaxAmount+"]", module);
-                // capturing to a billing account if amount is greater than zero
-                if (billingAccountCaptureAmount.compareTo(ZERO) == 1) {
-                    Map tmpResult = dispatcher.runSync("captureBillingAccountPayment", UtilMisc.toMap("invoiceId", invoiceId, "billingAccountId", billingAccountId,
-                            "captureAmount", new Double(billingAccountCaptureAmount.doubleValue()), "orderId", orderId, "userLogin", userLogin));
-                    if (ServiceUtil.isError(tmpResult)) {
-                        return tmpResult;
+        // Process billing accounts payments
+        if (UtilValidate.isNotEmpty(paymentPrefsBa)) {
+            Iterator paymentsBa = paymentPrefsBa.iterator();
+            while (paymentsBa.hasNext()) {
+                GenericValue paymentPref = (GenericValue) paymentsBa.next();
+
+                BigDecimal authAmount = paymentPref.getBigDecimal("maxAmount");
+                if (authAmount == null) authAmount = new BigDecimal(0.00);
+                authAmount = authAmount.setScale(2, BigDecimal.ROUND_HALF_UP);
+
+                if (authAmount.compareTo(ZERO) == 0) {
+                    // nothing to capture
+                    Debug.logInfo("Nothing to capture; authAmount = 0", module);
+                    continue;
+                }
+                // the amount for *this* capture
+                BigDecimal amountThisCapture = amountToCapture.min(authAmount);
+
+                // decrease amount of next payment preference to capture
+                amountToCapture = amountToCapture.subtract(amountThisCapture);
+
+                // If we have an invoice, we find unapplied payments associated
+                // to the billing account and we apply them to the invoice
+                if (UtilValidate.isNotEmpty(invoiceId)) {
+                    // TODO: jacopo continue from here...
+                    // cercare le paymentapplication non applicate e associate al billing account e il cui
+                    // pagamento non abbia una orderPaymentPreferenceId
+                    // creare nuova payment application fino a raggiungere l'importo necessario o fino ad esaurimento
+                    // e associarle alla fattura; se la fattura non esiste, non fare nulla
+                    Map captureResult = null;
+                    try {
+                        captureResult = dispatcher.runSync("captureBillingAccountPayments", UtilMisc.toMap("invoiceId", invoiceId,
+                                                                                                          "billingAccountId", billingAccountId,
+                                                                                                          "captureAmount", new Double(amountThisCapture.doubleValue()),
+                                                                                                          "orderId", orderId,
+                                                                                                          "userLogin", userLogin));
+                        if (ServiceUtil.isError(captureResult)) {
+                            return captureResult;
+                        }
+                    } catch (GenericServiceException ex) {
+                        return ServiceUtil.returnError(ex.getMessage());
                     }
+                    if (captureResult != null) {
+                        
+                        Double amountCaptured = (Double) captureResult.get("captureAmount");
+                        Debug.logInfo("Amount captured for order [" + orderId + "] from unapplied payments associated to billing account [" + billingAccountId + "] is: " + amountCaptured, module);
 
-                    // now, if the full amount had not been captured, then capture
-                    // it from other methods, otherwise return
-                    if (billingAccountCaptureAmount.compareTo(amountToCapture) == -1) {
-                        BigDecimal outstandingAmount = amountToCapture.subtract(billingAccountCaptureAmount).setScale(decimals, rounding);
-                        amountToCapture = outstandingAmount;
+                        // big decimal reference to the capture amount
+                        BigDecimal amountCapturedBd = new BigDecimal(amountCaptured.doubleValue());
+                        amountCapturedBd = amountCapturedBd.setScale(2, BigDecimal.ROUND_HALF_UP);
+
+                        if (amountCapturedBd.compareTo(BigDecimal.ZERO) == 0) {
+                            continue;
+                        }
+                        // add the invoiceId to the result for processing
+                        captureResult.put("invoiceId", invoiceId);
+                        captureResult.put("captureResult", Boolean.TRUE);
+                        captureResult.put("orderPaymentPreference", paymentPref);
+                        captureResult.put("captureRefNum", ""); // FIXME: this is an hack to avoid a service validation error for processCaptureResult (captureRefNum is mandatory, but it is not used for billing accounts)
+
+                        // process the capture's results
+                        try {
+                            // the following method will set on the OrderPaymentPreference:
+                            // maxAmount = amountCapturedBd and
+                            // statusId = PAYMENT_RECEIVED
+                            processResult(dctx, captureResult, userLogin, paymentPref);
+                        } catch (GeneralException e) {
+                            Debug.logError(e, "Trouble processing the result; captureResult: " + captureResult, module);
+                            return ServiceUtil.returnError("Trouble processing the capture results");
+                        }
+
+                        // create any splits which are needed
+                        if (authAmount.compareTo(amountCapturedBd) == 1) {
+                            BigDecimal splitAmount = authAmount.subtract(amountCapturedBd);
+                            try {
+                                Map splitCtx = UtilMisc.toMap("userLogin", userLogin, "orderPaymentPreference", paymentPref, "splitAmount", splitAmount);
+                                dispatcher.addCommitService("processCaptureSplitPayment", splitCtx, true);
+                            } catch (GenericServiceException e) {
+                                Debug.logWarning(e, "Problem processing the capture split payment", module);
+                            }
+                            Debug.logInfo("Captured: " + amountThisCapture + " Remaining (re-auth): " + splitAmount, module);
+                        }
                     } else {
-                        Debug.logInfo("Amount to capture [" + amountToCapture + "] was fully captured in Payment [" + tmpResult.get("paymentId") + "].", module);
-                        Map result = ServiceUtil.returnSuccess();
-                        result.put("processResult", "COMPLETE");
-                        return result;
+                        Debug.logError("Payment not captured for order [" + orderId + "] from billing account [" + billingAccountId + "]", module);
                     }
-               }
-            } catch (GenericServiceException ex) {
-                return ServiceUtil.returnError(ex.getMessage());
+                }
             }
-        }            
-        
-        // return complete if no payment prefs were found
-        // JAC20070602: Is this correct? Shouldn't we check if the
-        // amountToCapture is > 0 as we are doing
-        // at the bottom of this method?
-        if (paymentPrefs == null || paymentPrefs.size() == 0) {
-            Debug.logWarning("No orderPaymentPreferences available to capture", module);
-            Map result = ServiceUtil.returnSuccess();
-            result.put("processResult", "COMPLETE");
-            return result;
         }
 
-        if (Debug.infoOn()) Debug.logInfo("Actual Expected Capture Amount : " + amountToCapture, module);
-
         // iterate over the prefs and capture each one until we meet our total
         if (UtilValidate.isNotEmpty(paymentPrefs)) {
             Iterator payments = paymentPrefs.iterator();
@@ -1125,12 +1156,6 @@
                     continue;
                 }
 
-                // if we have a billing account; total up auth + account available
-                BigDecimal amountToBillAccount = ZERO;
-                if (billingAccountAvail != null) {
-                    amountToBillAccount = authAmount.add(billingAccountAvail).setScale(2, BigDecimal.ROUND_HALF_UP);
-                }
-
                 // the amount for *this* capture
                 BigDecimal amountThisCapture;
 
@@ -1141,9 +1166,6 @@
                 } else if (payments.hasNext()) {
                     // if we have more payments to capture; just capture what was authorized
                     amountThisCapture = authAmount;
-                } else if (billingAccountAvail != null && amountToBillAccount.compareTo(amountToCapture) >= 0) {
-                    // the provided billing account will cover the remaining; just capture what was autorized
-                    amountThisCapture = authAmount;
                 } else {
                     // we need to capture more then what was authorized; re-auth for the new amount
                     // TODO: add what the billing account cannot support to the re-auth amount
@@ -1153,7 +1175,6 @@
                     amountThisCapture = authAmount;
                 }
 
-                Debug.logInfo("Payment preference = [" + paymentPref + "] amount to capture = [" + amountToCapture +"] amount of this capture = [" + amountThisCapture +"] actual auth amount =[" + authAmount + "] amountToBillAccount = [" + amountToBillAccount + "]", module);
                 Map captureResult = capturePayment(dctx, userLogin, orh, paymentPref, amountThisCapture.doubleValue());
                 if (captureResult != null && !ServiceUtil.isError(captureResult)) {
                     // credit card processors return captureAmount, but gift certificate processors return processAmount
@@ -1272,6 +1293,7 @@
         return ServiceUtil.returnSuccess();
     }
 
+    // Deprecated: use captureBillingAccountPayments instead of this.
     public static Map captureBillingAccountPayment(DispatchContext dctx, Map context) {
         GenericDelegator delegator = dctx.getDelegator();
         LocalDispatcher dispatcher = dctx.getDispatcher();
@@ -1352,6 +1374,66 @@
             return ServiceUtil.returnError(ex.getMessage());
         }
 
+        return results;
+    }
+
+    public static Map captureBillingAccountPayments(DispatchContext dctx, Map context) {
+        GenericDelegator delegator = dctx.getDelegator();
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+        GenericValue userLogin = (GenericValue) context.get("userLogin");
+        String invoiceId = (String) context.get("invoiceId");
+        String billingAccountId = (String) context.get("billingAccountId");
+        Double captureAmountDbl = (Double) context.get("captureAmount");
+        BigDecimal captureAmount = new BigDecimal(captureAmountDbl.doubleValue());
+        String orderId = (String) context.get("orderId");
+        BigDecimal capturedAmount = BigDecimal.ZERO;
+        
+        try {
+            // Select all the unapplied payment applications associated to the billing account
+            List conditionList = UtilMisc.toList(new EntityExpr("billingAccountId", EntityOperator.EQUALS, billingAccountId),
+                                                  new EntityExpr("invoiceId", EntityOperator.EQUALS, GenericEntity.NULL_FIELD));
+            EntityCondition conditions = new EntityConditionList(conditionList, EntityOperator.AND);
+
+            List paymentApplications = delegator.findByCondition("PaymentApplication", conditions, null, UtilMisc.toList("-amountApplied"));
+            if (UtilValidate.isNotEmpty(paymentApplications)) {
+                Iterator paymentApplicationsIt = paymentApplications.iterator();
+                while (paymentApplicationsIt.hasNext()) {
+                    if (capturedAmount.compareTo(captureAmount) >= 0) {
+                        // we have captured all the amount required
+                        break;
+                    }
+                    GenericValue paymentApplication = (GenericValue)paymentApplicationsIt.next();
+                    GenericValue payment = paymentApplication.getRelatedOne("Payment");
+                    if (payment.getString("paymentPreferenceId") != null) {
+                        // if the payment is reserved for a specific OrderPaymentPreference,
+                        // we don't use it.
+                        continue;
+                    }
+                    // TODO: check the statusId of the payment
+                    BigDecimal paymentApplicationAmount = paymentApplication.getBigDecimal("amountApplied");
+                    BigDecimal amountToCapture = paymentApplicationAmount.min(captureAmount.subtract(capturedAmount));
+                    if (amountToCapture.compareTo(paymentApplicationAmount) == 0) {
+                        // apply the whole payment application to the invoice
+                        paymentApplication.set("invoiceId", invoiceId);
+                        paymentApplication.store();
+                    } else {
+                        // the amount to capture is lower than the amount available in this payment application:
+                        // split the payment application into two records and apply one to the invoice
+                        GenericValue newPaymentApplication = delegator.makeValue("PaymentApplication", paymentApplication);
+                        paymentApplication.set("invoiceId", invoiceId);
+                        paymentApplication.set("amountApplied", amountToCapture);
+                        paymentApplication.store();
+                        newPaymentApplication.set("amountApplied", paymentApplicationAmount.subtract(amountToCapture));
+                        newPaymentApplication.store();
+                    }
+                    capturedAmount = capturedAmount.add(amountToCapture);
+                }
+            }
+        } catch (GenericEntityException ex) {
+            return ServiceUtil.returnError(ex.getMessage());
+        }
+        Map results = ServiceUtil.returnSuccess();
+        results.put("captureAmount", new Double(capturedAmount.doubleValue()));
         return results;
     }
     

Modified: ofbiz/trunk/applications/accounting/widget/BillingAccountForms.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/widget/BillingAccountForms.xml?view=diff&rev=543923&r1=543922&r2=543923
==============================================================================
--- ofbiz/trunk/applications/accounting/widget/BillingAccountForms.xml (original)
+++ ofbiz/trunk/applications/accounting/widget/BillingAccountForms.xml Sun Jun  3 09:06:37 2007
@@ -46,11 +46,13 @@
                 </entity-options>
             </drop-down>
         </field>
+        <!--
         <field name="netBalance" title="${uiLabelMap.AccountingBillingNetBalance}" tooltip="${uiLabelMap.AccountingBillingNetBalanceMessage}">
             <display description="${bsh:org.ofbiz.accounting.payment.BillingAccountWorker.getBillingAccountNetBalance(delegator, billingAccountId)}" type="currency" currency="${billingAccount.accountCurrencyUomId}"/>
         </field>
+        -->
         <field name="availableBalance" title="${uiLabelMap.AccountingBillingAvailableBalance}" tooltip="${uiLabelMap.AccountingBillingAvailableBalanceMessage}">
-            <display description="${bsh:org.ofbiz.accounting.payment.BillingAccountWorker.getBillingAccountAvailableBalance(billingAccount)}" type="currency" currency="${billingAccount.accountCurrencyUomId}"/>
+            <display description="${bsh:org.ofbiz.accounting.payment.BillingAccountWorker.getBillingAccountBalance(billingAccount)}" type="currency" currency="${billingAccount.accountCurrencyUomId}"/>
         </field>
 
         <field name="submitButton" title="${uiLabelMap.CommonUpdate}" widget-style="smallSubmit"><submit button-type="button"/></field>

Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java?view=diff&rev=543923&r1=543922&r2=543923
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java (original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java Sun Jun  3 09:06:37 2007
@@ -1362,7 +1362,7 @@
         if (billingAccountId == null) return 0.0;
         try {
             Map res = dispatcher.runSync("calcBillingAccountBalance", UtilMisc.toMap("billingAccountId", billingAccountId));
-            Double availableBalance = (Double) res.get("availableBalance");
+            Double availableBalance = (Double) res.get("accountBalance");
             if (availableBalance != null) {
                 return availableBalance.doubleValue();
             }

Modified: ofbiz/trunk/applications/order/webapp/ordermgr/entry/billsettings.ftl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/webapp/ordermgr/entry/billsettings.ftl?view=diff&rev=543923&r1=543922&r2=543923
==============================================================================
--- ofbiz/trunk/applications/order/webapp/ordermgr/entry/billsettings.ftl (original)
+++ ofbiz/trunk/applications/order/webapp/ordermgr/entry/billsettings.ftl Sun Jun  3 09:06:37 2007
@@ -87,7 +87,7 @@
                 </tr>
                 <tr><td colspan="3"><hr class="sepbar"/></td></tr>
                 <#list billingAccountList as billingAccount>
-                  <#assign availableAmount = billingAccount.accountLimit?double - billingAccount.accountBalance?double>
+                  <#assign availableAmount = billingAccount.accountBalance?double>
                   <tr>
                     <td align="left" valign="top" width="1%">
                       <input type="radio" onClick="javascript:toggleBillingAccount(this);" name="billingAccountId" value="${billingAccount.billingAccountId}" <#if (billingAccount.billingAccountId == selectedBillingAccountId?default(""))>checked="checked"</#if>/>