Index: /main/waeup.sirp/trunk/src/waeup/sirp/payments/interfaces.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/payments/interfaces.py	(revision 6929)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/payments/interfaces.py	(revision 6930)
@@ -43,5 +43,5 @@
         )
 
-    payment_date = schema.Date(
+    payment_date = schema.Datetime(
         title = u'Payment Date',
         required = False,
@@ -100,9 +100,16 @@
     #    )
 
+    ac = schema.TextLine(
+        title = u'Activation Code',
+        default = None,
+        required = False,
+        readonly = False,
+        )
+
     r_amount_approved = schema.Int(
         title = u'Response Amount Approved',
         default = 0,
         required = False,
-        readonly = True,
+        readonly = False,
         )
 
@@ -111,5 +118,5 @@
         default = None,
         required = False,
-        readonly = True,
+        readonly = False,
         )
 
@@ -118,4 +125,4 @@
         default = None,
         required = False,
-        readonly = True,
+        readonly = False,
         )
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 6929)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 6930)
@@ -913,4 +913,32 @@
             self.context.__parent__.__parent__.fullname,self.context.p_id)
 
+class OnlinePaymentCallbackPage(grok.View):
+    """ Callback view
+    """
+    grok.context(IStudentOnlinePayment)
+    grok.name('callback')
+    grok.require('waeup.payStudent')
+
+    # This update method simulates a valid callback und must be
+    # specified in the customization package. The parameters must be taken
+    # from the incoming request.
+    def update(self):
+        self.context.r_amount_approved = self.context.amount_auth
+        self.context.r_card_num = u'0000'
+        self.context.r_code = u'00'
+        self.context.p_state = 'paid'
+        self.context.payment_date = datetime.now()
+        if self.context.p_category == 'clearance':
+            # Find valid CLR access code
+            pass
+        elif self.context.p_category == 'schoolfee':
+            # Find valid SFE access code
+            pass
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context))
+        return
+
 class AccommodationDisplayFormPage(WAeUPDisplayFormPage):
     """ Page to display the student accommodation data
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/permissions.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/permissions.py	(revision 6929)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/permissions.py	(revision 6930)
@@ -27,4 +27,7 @@
     grok.name('waeup.viewStudent')
 
+class PayStudent(grok.Permission):
+    grok.name('waeup.payStudent')
+
 class ManageStudents(grok.Permission):
     grok.name('waeup.manageStudents')
@@ -34,5 +37,6 @@
     grok.name('waeup.local.StudentRecordOwner')
     grok.title(u'Student Record Owner')
-    grok.permissions('waeup.handleStudent', 'waeup.viewStudent')
+    grok.permissions('waeup.handleStudent',
+                     'waeup.viewStudent', 'waeup.payStudent')
 
 # Global Roles
@@ -45,3 +49,4 @@
     grok.title(u'Students Officer')
     grok.permissions('waeup.View', 'waeup.Public',
-                     'waeup.viewStudent', 'waeup.manageStudents')
+                     'waeup.viewStudent', 'waeup.manageStudents',
+                     'waeup.payStudent')
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py	(revision 6929)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py	(revision 6930)
@@ -691,2 +691,13 @@
         self.assertMatches('...ticket created...',
                            self.browser.contents)
+
+        # Managers can open the callback view which simulates a valid callback
+        ctrl = self.browser.getControl(name='val_id')
+        value = ctrl.options[0]
+        self.browser.getLink(value).click()
+        self.browser.open(self.browser.url + '/callback')
+        expected = '''...
+        <td>
+          Paid
+        </td>...'''
+        self.assertMatches(expected,self.browser.contents)
