Index: main/waeup.kofa/trunk/src/waeup/kofa/students/export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 8368)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 8371)
@@ -24,5 +24,6 @@
 from waeup.kofa.interfaces import MessageFactory as _
 from waeup.kofa.students.interfaces import (
-    IStudent, IStudentStudyCourse, IStudentStudyLevel, ICourseTicket)
+    IStudent, IStudentStudyCourse, IStudentStudyLevel, ICourseTicket,
+    IStudentOnlinePayment)
 from waeup.kofa.utils.batching import ExporterBase
 from waeup.kofa.utils.helpers import iface_names
@@ -248,2 +249,55 @@
         return self.export(tickets, filepath)
 
+class PaymentsExporter(grok.GlobalUtility, ExporterBase):
+    """Exporter for OnlinePayment instances.
+    """
+    grok.implements(ICSVExporter)
+    grok.name('studentpayments')
+
+    #: Fieldnames considered by this exporter
+    fields = tuple(
+        sorted(['reg_number', 'matric_number'] +
+               iface_names(IStudentOnlinePayment, exclude_attribs=False)))
+
+    #: The title under which this exporter will be displayed
+    title = _(u'Course Tickets')
+
+    def mangle_value(self, value, name, context=None):
+        """Treat location values special.
+        """
+        if context is not None:
+            student = context.getStudent()
+            if name in ['reg_number', 'matric_number'] and student is not None:
+                value = getattr(student, name, None)
+        return super(
+            PaymentsExporter, self).mangle_value(
+            value, name, context=context)
+
+    def export(self, payments, filepath=None):
+        """Export `payments`, an iterable, as CSV file.
+
+        If `filepath` is ``None``, a raw string with CSV data is returned.
+        """
+        writer, outfile = self.get_csv_writer(filepath)
+        for payment in payments:
+            self.write_item(payment, writer)
+        return self.close_outfile(filepath, outfile)
+
+    def export_all(self, site, filepath=None):
+        """Export payments into filepath as CSV data.
+
+        If `filepath` is ``None``, a raw string with CSV data is returned.
+        """
+        catalog = queryUtility(
+            ICatalog, context=site, name='students_catalog', default=None)
+        if catalog is None:
+            return self.export([], filepath)
+        students = catalog.searchResults(
+            student_id=(None, None))
+        payments = []
+        for student in students:
+            if not 'payments' in student.keys():
+                continue
+            for payment in student['payments'].values():
+                payments.append(payment)
+        return self.export(payments, filepath)
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 8368)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py	(revision 8371)
@@ -1,2 +1,3 @@
+import datetime
 from zope.component import queryUtility
 from zope.interface.verify import verifyObject, verifyClass
@@ -4,5 +5,6 @@
 from waeup.kofa.students.export import (
     StudentsExporter, StudentStudyCourseExporter, StudentStudyLevelExporter,
-    CourseTicketExporter)
+    CourseTicketExporter, PaymentsExporter)
+from waeup.kofa.students.payments import StudentOnlinePayment
 from waeup.kofa.students.student import StudentStudyCourse
 from waeup.kofa.students.studylevel import StudentStudyLevel, CourseTicket
@@ -273,2 +275,97 @@
             )
         return
+
+class PaymentsExporterTest(StudentImportExportSetup):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(PaymentsExporterTest, self).setUp()
+        self.setup_for_export()
+        return
+
+    def get_payment(self):
+        # get a payment with all fields set
+        payment = StudentOnlinePayment()
+        payment.creation_date = datetime.datetime(2012, 4, 1, 13, 12, 1)
+        payment.p_id = 'my-id'
+        payment.ac = u'666'
+        payment.p_item = u'p-item'
+        payment.p_level = 100
+        payment.p_session = 2012
+        payment.payment_date = datetime.datetime(2012, 4, 1, 14, 12, 1)
+        payment.r_amount_approved = 12.12
+        payment.r_code = u'r-code'
+        # XXX: there is no addPayment method to give predictable names
+        self.student['payments']['my-payment'] = payment
+        return payment
+
+    def test_ifaces(self):
+        # make sure we fullfill interface contracts
+        obj = PaymentsExporter()
+        verifyObject(ICSVExporter, obj)
+        verifyClass(ICSVExporter, PaymentsExporter)
+        return
+
+    def test_get_as_utility(self):
+        # we can get a payments exporter as utility
+        result = queryUtility(ICSVExporter, name="studentpayments")
+        self.assertTrue(result is not None)
+        return
+
+    def test_export_empty(self):
+        # we can export a nearly empty payment
+        payment = StudentOnlinePayment()
+        payment.creation_date = datetime.datetime(2012, 4, 1, 13, 12, 1)
+        exporter = PaymentsExporter()
+        exporter.export([payment], self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'ac,amount_auth,creation_date,matric_number,p_category,p_id,'
+            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
+            'r_code,reg_number\r\n'
+
+            ',0.0,2012-04-01 13:12:01,,schoolfee,,,,,unpaid,,0.0,,\r\n'
+            )
+        return
+
+    def test_export(self):
+        # we can really export student payments.
+        # set values we can expect in export file
+        self.setup_student(self.student)
+        payment = self.get_payment()
+        exporter = PaymentsExporter()
+        exporter.export([payment], self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'ac,amount_auth,creation_date,matric_number,p_category,p_id,'
+            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
+            'r_code,reg_number\r\n'
+
+            '666,0.0,2012-04-01 13:12:01,M123456,schoolfee,my-id,'
+            'p-item,100,2012,unpaid,2012-04-01 14:12:01,12.12,'
+            'r-code,123456\r\n'
+            )
+        return
+
+    def test_export_all(self):
+        # we can really export all payments
+        # set values we can expect in export file
+        self.setup_student(self.student)
+        self.get_payment() # adds new payment to student
+        exporter = PaymentsExporter()
+        exporter.export_all(self.app, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'ac,amount_auth,creation_date,matric_number,p_category,p_id,'
+            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
+            'r_code,reg_number\r\n'
+
+            '666,0.0,2012-04-01 13:12:01,M123456,schoolfee,my-id,'
+            'p-item,100,2012,unpaid,2012-04-01 14:12:01,12.12,'
+            'r-code,123456\r\n'
+            )
+        return
