Index: main/waeup.kofa/trunk/CHANGES.txt
===================================================================
--- main/waeup.kofa/trunk/CHANGES.txt	(revision 17015)
+++ main/waeup.kofa/trunk/CHANGES.txt	(revision 17016)
@@ -4,4 +4,7 @@
 1.7.2.dev0 (unreleased)
 =======================
+
+* Add `BalancePaymentAddFormPage` which can only be opened by managers.
+  No button is provided in base package.
 
 * Do not require session configuration object for application payments.
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py	(revision 17015)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py	(revision 17016)
@@ -41,5 +41,6 @@
     IApplicantOnlinePayment, IApplicantsUtils,
     IApplicantRegisterUpdate, ISpecialApplicant,
-    IApplicantRefereeReport
+    IApplicantRefereeReport,
+    IApplicantBalancePayment
     )
 from waeup.kofa.utils.helpers import (html2dict,
@@ -831,4 +832,45 @@
     def render(self):
         return
+        
+class BalancePaymentAddFormPage(KofaAddFormPage):
+    """ Page to add an online payment which can balance s previous session
+    payment.
+    """
+    grok.context(IApplicant)
+    grok.name('addbp')
+    grok.template('balancepaymentaddform')
+    grok.require('waeup.manageApplication')
+    form_fields = grok.AutoFields(IApplicantBalancePayment)
+    label = _('Add balance')
+    #pnav = 4
+
+    @property
+    def selectable_payment_options(self):
+        options = getUtility(
+            IKofaUtils).selectable_payment_options(self.context)
+        return sorted(options.items(), key=lambda value: value[1])
+
+    @action(_('Create ticket'), style='primary')
+    def createTicket(self, **data):
+        p_category = data['p_category']
+        p_option = data.get('p_option', None)
+        balance_amount = data.get('balance_amount', None)
+        applicants_utils = getUtility(IApplicantsUtils)
+        error, payment = applicants_utils.setBalanceDetails(
+            self.context, p_category, balance_amount)
+        if error is not None:
+            self.flash(error, type="danger")
+            return
+        if p_option:
+            payment.p_option = p_option
+        self.context[payment.p_id] = payment
+        self.flash(_('Payment ticket created.'))
+        self.context.writeLogMessage(self,'added: %s' % payment.p_id)
+        self.redirect(self.url(payment))
+        return
+
+    @action(_('Cancel'), validator=NullValidator)
+    def cancel(self, **data):
+        self.redirect(self.url(self.context))
 
 
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser_templates/balancepaymentaddform.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser_templates/balancepaymentaddform.pt	(revision 17016)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser_templates/balancepaymentaddform.pt	(revision 17016)
@@ -0,0 +1,30 @@
+<form action="." tal:attributes="action request/URL" method="post"
+      enctype="multipart/form-data" i18n:domain="waeup.kofa">
+
+  <table class="form-table">
+    <tbody>
+      <tal:widgets content="structure provider:widgets" />
+      <tr tal:condition="view/selectable_payment_options">
+        <td i18n:translate="" class="fieldname">
+          Payment Option:
+        </td>
+        <td>
+          <select id="form.p_option" name="form.p_option" size="1"
+                  class="form-control half" onclick="further()">
+            <option tal:repeat="item view/selectable_payment_options"
+                    tal:attributes="value python:item[0]">
+              <span tal:replace="python:item[1]">PAYMENT OPTION</span>
+            </option>
+          </select>
+        </td>
+      </tr>
+      <tal:files content="structure provider:files" />
+    </tbody>
+  </table>
+  <br />
+  <div tal:condition="view/availableActions">
+    <input tal:repeat="action view/actions"
+           tal:replace="structure action/render"
+           />
+  </div>
+</form>
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/interfaces.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/interfaces.py	(revision 17015)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/interfaces.py	(revision 17016)
@@ -30,5 +30,5 @@
 from waeup.kofa.interfaces import (
     IKofaObject, validate_email, validate_html,
-    SimpleKofaVocabulary)
+    SimpleKofaVocabulary, ContextualDictSourceFactoryBase)
 from waeup.kofa.interfaces import MessageFactory as _
 from waeup.kofa.payments.interfaces import IOnlinePayment
@@ -45,4 +45,10 @@
     curr_year = datetime.now().year
     return range(curr_year - 6, curr_year + 5)
+
+class ApplicantBalancePaymentCategorySource(ContextualDictSourceFactoryBase):
+    """A source that delivers all selectable items of balance payments.
+    """
+    #: name of dict to deliver from kofa utils.
+    DICT_NAME = 'APPLICANT_BALANCE_PAYMENT_CATEGORIES'
 
 class RegNumInSource(ValidationError):
@@ -693,4 +699,24 @@
         """Approve payment and process applicant.
         """
+        
+class IApplicantBalancePayment(IKofaObject):
+    """An interface for adding balances.
+    """
+
+    p_category = schema.Choice(
+        title = _(u'Payment Category'),
+        default = u'application',
+        required = True,
+        source = ApplicantBalancePaymentCategorySource(),
+        )
+
+    balance_amount = schema.Float(
+        title = _(u'Balance Amount'),
+        default = None,
+        required = True,
+        readonly = False,
+        description = _(
+            u'Balance in Naira '),
+        )
 
 class IApplicantRefereeReport(IKofaObject):
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py	(revision 17015)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py	(revision 17016)
@@ -1086,4 +1086,22 @@
         return
 
+    def test_pay_balance(self):
+        # Managers can make balance payment
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.manage_path)
+        self.fill_correct_values()
+        self.browser.getControl("Save").click()
+        self.browser.open(self.view_path + '/addbp')
+        self.browser.getControl(name="form.p_category").value = ['donation']
+        self.browser.getControl(name="form.balance_amount").value = '10000'
+        self.browser.getControl("Create ticket").click()
+        self.assertTrue('Wrong state' in self.browser.contents)
+        IWorkflowState(self.applicant).setState('submitted')
+        self.browser.getControl("Create ticket").click()
+        self.assertTrue('Payment ticket created.' in self.browser.contents)
+        self.browser.getLink("Approve payment").click()
+        self.assertTrue('Payment approved' in self.browser.contents)
+        return
+
     def prepare_special_container(self):
         # Add special application container
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/utils.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/utils.py	(revision 17015)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/utils.py	(revision 17016)
@@ -22,5 +22,5 @@
 from datetime import datetime
 import grok
-from zope.component import getUtility
+from zope.component import getUtility, createObject
 from zope.catalog.interfaces import ICatalog
 from waeup.kofa.interfaces import MessageFactory as _
@@ -89,4 +89,26 @@
         return
 
+    def setBalanceDetails(self, applicant, category, balance_amount):
+        """Create a balance payment ticket and set the payment data
+        as selected by the applicant.
+        """
+        if applicant.state not in (PAID, ADMITTED, SUBMITTED, PROCESSED):
+            return _('Wrong state.'), None
+        p_item = u'Balance'
+        amount = balance_amount
+        if amount in (0.0, None) or amount < 0:
+            return _('Amount must be greater than 0.'), None
+        payment = createObject(u'waeup.ApplicantOnlinePayment')
+        timestamp = ("%d" % int(time()*10000))[1:]
+        payment.p_id = "p%s" % timestamp
+        payment.p_category = category
+        payment.p_item = p_item
+        if applicant.__parent__.year:
+            payment.p_session = applicant.__parent__.year
+        else:
+            payment.p_session = datetime.now().year
+        payment.amount_auth = amount
+        return None, payment
+
     def getApplicantsStatistics(self, container):
         """Count applicants in applicants containers.
Index: main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py	(revision 17015)
+++ main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py	(revision 17016)
@@ -194,4 +194,5 @@
         'late_registration': 'Late Course Registration Fee',
         'combi': 'Combi Payment',
+        'donation': 'Donation',
         }
 
@@ -219,4 +220,8 @@
     BALANCE_PAYMENT_CATEGORIES = {
         'schoolfee': 'School Fee',
+        }
+
+    APPLICANT_BALANCE_PAYMENT_CATEGORIES = {
+        'donation': 'Donation',
         }
 
