diff --git a/product/ERP5/Document/BudgetLine.py b/product/ERP5/Document/BudgetLine.py
index 2e321ce597bbdeafb5a53ef2610000a2ce2f1248..eeaa11a95320daa380c3bd21c14e280ac728b0d2 100644
--- a/product/ERP5/Document/BudgetLine.py
+++ b/product/ERP5/Document/BudgetLine.py
@@ -83,6 +83,25 @@ class BudgetLine(Predicate, XMLMatrix, Variated):
                   self.getPortalTransitInventoryStateList())
     return self._getBudgetDict(**kw)
 
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getAvailableBudgetDict')
+  def getAvailableBudgetDict(self, **kw):
+    """Returns all the engagements in a dict where the keys are the cells, and
+    the value is the engaged budget.
+    """
+    budget_dict =  dict([(k, v * -1) for (k,v) in
+                         self.getEngagedBudgetDict(**kw).items()])
+    
+    cell_key_list = self.getCellKeyList()
+    for cell_key in cell_key_list:
+      cell_key = tuple(cell_key)
+      cell = self.getCell(*cell_key)
+      if cell is not None:
+        engaged = budget_dict.get(cell_key, 0)
+        budget_dict[cell_key] = cell.getCurrentBalance() + engaged
+
+    return budget_dict
+
   def _getBudgetDict(self, **kw):
     """Use getCurrentInventoryList to compute all budget cell consumptions at
     once, and returns them in a dict.
diff --git a/product/ERP5/tests/testBudget.py b/product/ERP5/tests/testBudget.py
index 5fc89b3d461dcece60bf937ee32131563d1aae72..7578591fcfd66efadd79393949f4e4cfbb9a810b 100644
--- a/product/ERP5/tests/testBudget.py
+++ b/product/ERP5/tests/testBudget.py
@@ -363,7 +363,17 @@ class TestBudget(ERP5TypeTestCase):
       {('source/account_module/fixed_assets', 'account_type/asset'): -100.0,
        ('source/account_module/goods_purchase', 'account_type/expense'): 100.0},
         budget_line.getEngagedBudgetDict())
+
+    self.assertEquals(
+      {('source/account_module/fixed_assets', 'account_type/asset'): 102.0,
+       ('source/account_module/goods_purchase', 'account_type/expense'): -99.0},
+        budget_line.getAvailableBudgetDict())
       
+    # we can view the forms without error
+    budget_line.BudgetLine_viewEngagedBudget()
+    budget_line.BudgetLine_viewConsumedBudget()
+    budget_line.BudgetLine_viewAvailableBudget()
+
   def test_all_other_and_strict_consumption(self):
     # tests consumptions, by using "all other" virtual node on a node budget
     # variation, and strict membership on category budget variation
@@ -476,6 +486,11 @@ class TestBudget(ERP5TypeTestCase):
       {('source/%s' % budget_line.getRelativeUrl(), 'account_type/asset'): -100.0,
        ('source/account_module/goods_purchase', 'account_type/expense'): 100.0},
         budget_line.getEngagedBudgetDict())
+
+    self.assertEquals(
+      {('source/%s' % budget_line.getRelativeUrl(), 'account_type/asset'): 102.0,
+       ('source/account_module/goods_purchase', 'account_type/expense'): -99.0},
+        budget_line.getAvailableBudgetDict())
       
 
   def test_consumption_movement_category(self):
@@ -612,6 +627,15 @@ class TestBudget(ERP5TypeTestCase):
        },
         budget_line.getEngagedBudgetDict())
 
+    self.assertEquals(
+      {('source/account_module/fixed_assets', 'product_line/1/1.2'): 100.0,
+       ('source/account_module/goods_purchase', 'product_line/1/1.1'): -98.0,
+       # summary line is automatically added (TODO)
+##       ('source/account_module/goods_purchase', 'product_line/1'): 98.0 
+       ('source/account_module/goods_purchase', 'product_line/1'): 2.0 
+       },
+        budget_line.getAvailableBudgetDict())
+
 
     # Other TODOs: