Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15254)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15277)
@@ -3567,7 +3567,9 @@
     def _set_exporter_values(self):
         # We provide all student exporters, nothing else, yet.
-        # Bursary or Department Officers don't have the general exportData 
-        # permission and are only allowed to export bursary or payments
-        # overview data respectively. This is the only place where
+        # Bursary, Department or Accommodation Officers don't
+        # have the general exportData
+        # permission and are only allowed to export bursary, payments
+        # overview or accommodation data respectively.
+        # This is the only place where waeup.exportAccommodationData,
         # waeup.exportBursaryData and waeup.exportPaymentsOverview
         # are used.
@@ -3581,4 +3583,8 @@
                               ('Session Payments Overview',
                                'sessionpaymentsoverview')]
+            if checkPermission('waeup.exportAccommodationData', self.context):
+                exporters += [('Bed Tickets', 'bedtickets'),
+                              ('Accommodation Payments',
+                               'accommodationpayments')]
             self.exporters = exporters
             return
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 15254)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 15277)
@@ -508,4 +508,24 @@
             value, name, context=context)
 
+class AccommodationPaymentsExporter(DataForBursaryExporter):
+    """The AccommodationPayments Exporter works just like the Student
+    Payment Exporter but it exports much more information about the student.
+    It combines     payment and student data in one table in order to spare
+    postprocessing of     two seperate export files. The exporter is primarily
+    used by bursary officers who have exclusively access to this exporter.
+    The exporter exports ``paid`` and ``waived`` payment tickets with category
+    ``bed_allocation`` or ``hostel_maintenance``.
+    """
+    grok.name('accommodationpayments')
+
+    def filter_func(self, x, **kw):
+        kw['paycat'] = 'bed_allocation'
+        payments = get_payments(x, p_states=('paid', 'waived'), **kw)
+        kw['paycat'] = 'hostel_maintenance'
+        payments += get_payments(x, p_states=('paid', 'waived'), **kw)
+        return payments
+
+    title = _(u'Accommodation Payments')
+
 class BedTicketExporter(grok.GlobalUtility, StudentExporterBase):
     """The Bed Ticket Exporter first filters the set of students
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15254)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15277)
@@ -4181,4 +4181,47 @@
         self.assertEqual(len(self.app['datacenter'].running_exports), 0)
 
+    def test_export_accommodation_officers(self):
+        # Create bursary officer
+        self.app['users'].addUser('mracco', 'mraccosecret')
+        self.app['users']['mracco'].email = 'mracco@foo.ng'
+        self.app['users']['mracco'].title = 'Carlo Pitter'
+        prmglobal = IPrincipalRoleManager(self.app)
+        prmglobal.assignRoleToPrincipal('waeup.AccommodationOfficer', 'mracco')
+        # Login as bursary officer
+        self.browser.open(self.login_path)
+        self.browser.getControl(name="form.login").value = 'mracco'
+        self.browser.getControl(name="form.password").value = 'mraccosecret'
+        self.browser.getControl("Login").click()
+        self.assertMatches('...You logged in...', self.browser.contents)
+        self.browser.getLink("Academics").click()
+        self.browser.getLink("Export student data").click()
+        self.browser.getControl("Configure new export").click()
+        # accommodationpayments and beds exporters are available
+        # not only at facultiescontainer level ...
+        self.assertFalse('<option value="students">' in self.browser.contents)
+        self.assertTrue('<option value="accommodationpayments">'
+            in self.browser.contents)
+        self.assertTrue('<option value="bedtickets">' in self.browser.contents)
+        self.browser.getControl(
+            name="exporter").value = ['accommodationpayments']
+        self.browser.getControl(name="session").value = ['2004']
+        self.browser.getControl(name="level").value = ['100']
+        self.browser.getControl("Create CSV file").click()
+        self.assertTrue('Export started' in self.browser.contents)
+        # ... but also at other levels
+        self.browser.open('http://localhost/app/faculties/fac1/dep1')
+        self.browser.getLink("Export student data").click()
+        self.browser.getControl("Configure new export").click()
+        self.assertFalse('<option value="students">' in self.browser.contents)
+        self.assertTrue('<option value="accommodationpayments">'
+            in self.browser.contents)
+        self.assertTrue('<option value="bedtickets">' in self.browser.contents)
+        # Thew job can be discarded
+        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
+        self.wait_for_export_job_completed()
+        self.browser.open('http://localhost/app/faculties/exports')
+        self.browser.getControl("Discard").click()
+        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
+
 
 UPLOAD_CSV_TEMPLATE = (
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py	(revision 15254)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py	(revision 15277)
@@ -33,5 +33,5 @@
     ComboCardDataExporter, DataForBursaryExporter,
     StudentUnpaidPaymentExporter, SessionPaymentsOverviewExporter,
-    get_students,)
+    AccommodationPaymentsExporter, get_students,)
 from waeup.kofa.students.accommodation import BedTicket
 from waeup.kofa.students.interfaces import ICSVStudentExporter
@@ -1043,4 +1043,66 @@
             'Anna,M.,Tester,created,2012,2010,ug_ft,NA,NA,CERT1\r\n'
             % (curr_year-6, curr_year-6, curr_year-6)
+            )
+        return
+
+class AccommodationPaymentsExporterTest(StudentImportExportSetup):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(AccommodationPaymentsExporterTest, self).setUp()
+        self.setup_for_export()
+        return
+
+    def test_export_all(self):
+        self.setup_student(self.student)
+        # add accommodation payments
+        payment = StudentOnlinePayment()
+        payment.creation_date = datetime.datetime(curr_year-6, 4, 1, 13, 12, 1)
+        payment.p_id = 'id1'
+        payment.p_category = u'bed_allocation'
+        payment.p_state = 'paid'
+        payment.ac = u'abc'
+        payment.p_item = u'xyz'
+        payment.p_level = 100
+        payment.p_session = curr_year - 6
+        payment.payment_date = datetime.datetime(curr_year-6, 4, 1, 14, 12, 1)
+        payment.amount_auth = 12.12
+        payment.r_amount_approved = 12.12
+        payment.r_code = u'cde'
+        payment2 = StudentOnlinePayment()
+        payment2.creation_date = datetime.datetime(curr_year-6, 4, 1, 13, 12, 1)
+        payment2.p_id = 'id2'
+        payment2.p_category = u'hostel_maintenance'
+        payment2.p_state = 'paid'
+        payment2.ac = u'abc'
+        payment2.p_item = u'xyz'
+        payment2.p_level = 100
+        payment2.p_session = curr_year - 6
+        payment2.payment_date = datetime.datetime(curr_year-6, 4, 1, 14, 12, 1)
+        payment2.amount_auth = 12.12
+        payment2.r_amount_approved = 12.12
+        payment2.r_code = u'cde'
+        # XXX: there is no addPayment method to give predictable names
+        self.payment = self.student['payments']['id1'] = payment
+        self.payment = self.student['payments']['id2'] = payment2
+        exporter = AccommodationPaymentsExporter()
+        exporter.export_all(self.app, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        # only accommodation payments are exported
+        self.assertEqual(
+            result,
+            'ac,amount_auth,creation_date,p_category,p_current,p_id,p_item,'
+            'p_level,p_session,p_state,payment_date,r_amount_approved,r_code,'
+            'r_desc,student_id,matric_number,reg_number,firstname,middlename,lastname,'
+            'state,current_session,entry_session,entry_mode,faccode,depcode,certcode\r\n'
+            'abc,12.12,%s-04-01 13:12:01#,bed_allocation,1,id1,xyz,100,%s,'
+            'paid,%s-04-01 14:12:01#,12.12,cde,,A111111,234,123,'
+            'Anna,M.,Tester,created,2012,2010,ug_ft,NA,NA,CERT1\r\n'
+            'abc,12.12,%s-04-01 13:12:01#,hostel_maintenance,1,id2,xyz,100,%s,'
+            'paid,%s-04-01 14:12:01#,12.12,cde,,A111111,234,123,'
+            'Anna,M.,Tester,created,2012,2010,ug_ft,NA,NA,CERT1\r\n'
+            % (curr_year-6, curr_year-6, curr_year-6,
+               curr_year-6, curr_year-6, curr_year-6)
             )
         return
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py	(revision 15254)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py	(revision 15277)
@@ -1114,5 +1114,6 @@
             'studentpayments', 'studentunpaidpayments',
             'bedtickets', 'sfpaymentsoverview', 'sessionpaymentsoverview',
-            'studylevelsoverview', 'combocard', 'bursary')
+            'studylevelsoverview', 'combocard', 'bursary',
+            'accommodationpayments')
 
     #: A tuple containing all exporter names needed for backing
