Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15039)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15042)
@@ -3371,21 +3371,28 @@
     def _set_session_values(self):
         vocab_terms = academic_sessions_vocab.by_value.values()
-        self.sessions = sorted(
+        self.sessions = [(_('All Sessions'), 'all')]
+        self.sessions += sorted(
             [(x.title, x.token) for x in vocab_terms], reverse=True)
-        self.sessions += [(_('All Sessions'), 'all')]
         return
 
     def _set_level_values(self):
         vocab_terms = course_levels.by_value.values()
-        self.levels = sorted(
+        self.levels = [(_('All Levels'), 'all')]
+        self.levels += sorted(
             [(x.title, x.token) for x in vocab_terms])
-        self.levels += [(_('All Levels'), 'all')]
         return
 
     def _set_mode_values(self):
         utils = getUtility(IKofaUtils)
-        self.modes = sorted([(value, key) for key, value in
+        self.modes =[(_('All Modes'), 'all')]
+        self.modes += sorted([(value, key) for key, value in
                       utils.STUDY_MODES_DICT.items()])
-        self.modes +=[(_('All Modes'), 'all')]
+        return
+
+    def _set_paycat_values(self):
+        utils = getUtility(IKofaUtils)
+        self.paycats =[(_('All Payment Categories'), 'all')]
+        self.paycats += sorted([(value, key) for key, value in
+                      utils.PAYMENT_CATEGORIES.items()])
         return
 
@@ -3426,9 +3433,10 @@
 
     def update(self, START=None, session=None, level=None, mode=None,
-               payments_start=None, payments_end=None,
-               exporter=None):
+               payments_start=None, payments_end=None, ct_level=None, 
+               ct_session=None, paycat=None, exporter=None):
         self._set_session_values()
         self._set_level_values()
         self._set_mode_values()
+        self._set_paycat_values()
         self._set_exporter_values()
         if START is None:
@@ -3453,8 +3461,4 @@
         if mode == 'all':
             mode = None
-        if payments_start == '':
-            payments_start = None
-        if payments_end == '':
-            payments_end = None
         if (mode,
             level,
@@ -3464,38 +3468,32 @@
             self.certcode) == (None, None, None, None, None, None):
             # Export all students including those without certificate
-            if payments_start:
-                job_id = self.context.start_export_job(exporter,
-                                              self.request.principal.id,
-                                              payments_start = payments_start,
-                                              payments_end = payments_end)
-            else:
-                job_id = self.context.start_export_job(exporter,
-                                              self.request.principal.id)
-        else:
-            if payments_start:
-                job_id = self.context.start_export_job(exporter,
-                                              self.request.principal.id,
-                                              current_session=session,
-                                              current_level=level,
-                                              current_mode=mode,
-                                              faccode=self.faccode,
-                                              depcode=self.depcode,
-                                              certcode=self.certcode,
-                                              payments_start = payments_start,
-                                              payments_end = payments_end)
-            else:
-                job_id = self.context.start_export_job(exporter,
-                                              self.request.principal.id,
-                                              current_session=session,
-                                              current_level=level,
-                                              current_mode=mode,
-                                              faccode=self.faccode,
-                                              depcode=self.depcode,
-                                              certcode=self.certcode)
+            job_id = self.context.start_export_job(exporter,
+                                          self.request.principal.id,
+                                          payments_start = payments_start,
+                                          payments_end = payments_end,
+                                          paycat=paycat,
+                                          ct_level = ct_level,
+                                          ct_session = ct_session,
+                                          )
+        else:
+            job_id = self.context.start_export_job(exporter,
+                                          self.request.principal.id,
+                                          current_session=session,
+                                          current_level=level,
+                                          current_mode=mode,
+                                          faccode=self.faccode,
+                                          depcode=self.depcode,
+                                          certcode=self.certcode,
+                                          payments_start = payments_start,
+                                          payments_end = payments_end,
+                                          paycat=paycat,
+                                          ct_level = ct_level,
+                                          ct_session = ct_session,)
         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
         self.context.logger.info(
-            '%s - exported: %s (%s, %s, %s, %s, %s, %s, %s, %s), job_id=%s'
+            '%s - exported: %s (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s), job_id=%s'
             % (ob_class, exporter, session, level, mode, self.faccode,
-            self.depcode, self.certcode, payments_start, payments_end, job_id))
+            self.depcode, self.certcode, payments_start, payments_end,
+            ct_level, ct_session, paycat, job_id))
         self.flash(_('Export started for students with') +
                    ' current_session=%s, current_level=%s, study_mode=%s' % (
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportconfig.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportconfig.pt	(revision 15039)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportconfig.pt	(revision 15042)
@@ -67,4 +67,17 @@
   </span>
 
+  <span id="paycat" style="display: none;">
+    <br />
+    <label for="paycat" i18n:translate="">
+      Payment Categories
+    </label>
+    <select name="paycat" class="form-control half">
+      <option tal:repeat="item view/paycats"
+              tal:attributes="value python:item[1]">
+        <span tal:replace="python: item[0]">schoolfee</span>
+      </option>
+    </select>
+    <br />
+  </span>
 
   <span id="ct_data" style="display: none;">
@@ -91,4 +104,5 @@
     <br />
   </span>
+
   <br />
 
@@ -104,11 +118,14 @@
           document.getElementById('exporter').value == 'studentunpaidpayments') {
           document.getElementById('payment_dates').style.display = 'block';
+          document.getElementById('paycat').style.display = 'block';
           document.getElementById('ct_data').style.display = 'none';
       } else if (document.getElementById('exporter').value == 'coursetickets')  {
           document.getElementById('ct_data').style.display = 'block';
           document.getElementById('payment_dates').style.display = 'none';
+          document.getElementById('paycat').style.display = 'none';
       } else {
           document.getElementById('ct_data').style.display = 'none';
           document.getElementById('payment_dates').style.display = 'none';
+          document.getElementById('paycat').style.display = 'none';
       }
   }
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 15039)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 15042)
@@ -135,42 +135,23 @@
     payments_start = kw.get('payments_start')
     payments_end = kw.get('payments_end')
-    if payments_start and payments_end:
-        # Payment period given
-        payments_start = datetime.strptime(payments_start, date_format)
-        payments_end = datetime.strptime(payments_end, date_format)
-        tz = getUtility(IKofaUtils).tzinfo
-        payments_start = tz.localize(payments_start)
-        payments_end = tz.localize(payments_end) + timedelta(days=1)
-        if p_states:
-            # Only tickets in certain states and payment period are considered
-            for student in students:
-                for payment in student.get('payments', {}).values():
-                    if payment.payment_date and payment.p_state in p_states:
-                        payment_date = to_timezone(payment.payment_date, tz)
-                        if payment_date > payments_start and \
-                            payment_date < payments_end:
-                            payments.append(payment)
-        else:
-            # All tickets in payment period are considered
-            for student in students:
-                for payment in student.get('payments', {}).values():
-                    if payment.payment_date:
-                        payment_date = to_timezone(payment.payment_date, tz)
-                        if payment_date > payments_start and \
-                            payment_date < payments_end:
-                            payments.append(payment)
-    else:
-        # Payment period not given
-        if p_states:
-            # Only paid tickets are considered
-            for student in students:
-                for payment in student.get('payments', {}).values():
-                    if payment.p_state in p_states:
-                        payments.append(payment)
-        else:
-            # All tickets are considered
-            for student in students:
-                for payment in student.get('payments', {}).values():
-                    payments.append(payment)
+    paycat = kw.get('paycat')
+    for student in students:
+        for payment in student.get('payments', {}).values():
+            if payments_start and payments_end:
+                if not payment.payment_date:
+                    continue
+                payments_start = datetime.strptime(payments_start, date_format)
+                payments_end = datetime.strptime(payments_end, date_format)
+                tz = getUtility(IKofaUtils).tzinfo
+                payments_start = tz.localize(payments_start)
+                payments_end = tz.localize(payments_end) + timedelta(days=1)
+                payment_date = to_timezone(payment.payment_date, tz)
+                if payment_date < payments_start or payment_date > payments_end:
+                    continue
+            if p_states and not payment.p_state in p_states:
+                continue
+            if paycat not in ('all', None) and payment.p_category != paycat:
+                continue
+            payments.append(payment)
     return payments
 
@@ -218,11 +199,16 @@
                 students.append(ticket.student)
             return list(set(students))
-        # Payments can be filtered by payment_date. The period boundaries
-        # are not keys of the catalog and must thus be removed from kw.
+        # Payments can be filtered by payment date and payment category.
+        # These parameters are not keys of the catalog and must thus be
+        # removed from kw.
         try:
             del kw['payments_start']
             del kw['payments_end']
+            del kw['paycat']
         except KeyError:
             pass
+        # Coursetickets can be filtered level and session.
+        # These parameters are not keys of the catalog and must thus be
+        # removed from kw.
         try:
             del kw['ct_level']
@@ -433,5 +419,5 @@
     by searching the students catalog. Then it exports student payment
     tickets by iterating over the items of the student's ``payments``
-    container. If the payment period is given only tickets, which were
+    container. If the payment period is given, only tickets, which were
     paid in payment period, are considered for export.
     """
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 15039)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15042)
@@ -42,4 +42,5 @@
 from waeup.kofa.app import University
 from waeup.kofa.payments.interfaces import IPayer
+from waeup.kofa.students.payments import StudentOnlinePayment
 from waeup.kofa.students.student import Student
 from waeup.kofa.students.studylevel import StudentStudyLevel
@@ -58,4 +59,5 @@
 URL_LECTURER_LANDING = 'http://localhost/app/my_courses'
 
+curr_year = datetime.now().year
 
 def lookup_submit_value(name, value, browser):
@@ -3484,4 +3486,23 @@
         return job_id
 
+    def add_payment(self, student):
+        # get a payment with all fields set
+        payment = StudentOnlinePayment()
+        payment.creation_date = datetime(2012, 12, 13)
+        payment.p_id = 'my-id'
+        payment.p_category = u'schoolfee'
+        payment.p_state = 'paid'
+        payment.ac = u'666'
+        payment.p_item = u'p-item'
+        payment.p_level = 100
+        payment.p_session = curr_year - 6
+        payment.payment_date = datetime(2012, 12, 13)
+        payment.amount_auth = 12.12
+        payment.r_amount_approved = 12.12
+        payment.r_code = u'r-code'
+        # XXX: there is no addPayment method to give predictable names
+        self.payment = student['payments']['my-payment'] = payment
+        return payment
+
     def test_datacenter_export(self):
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
@@ -3518,5 +3539,5 @@
             'zope.mgr - students.browser.DatacenterExportJobContainerJobConfig '
             '- exported: bursary (2004, 100, ug_ft, None, None, None, '
-            '13/12/2012, 14/12/2012), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -3572,4 +3593,5 @@
 
     def test_faculties_export(self):
+        self.add_payment(self.student)
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
         facs_path = 'http://localhost/app/faculties'
@@ -3583,4 +3605,5 @@
         self.browser.getControl(name="payments_start").value = '13/12/2012'
         self.browser.getControl(name="payments_end").value = '14/12/2012'
+        self.browser.getControl(name="paycat").value = ['schoolfee']
         self.browser.getControl("Create CSV file").click()
 
@@ -3595,4 +3618,8 @@
             'filename="WAeUP.Kofa_bursary_%s.csv' % job_id in
             self.browser.headers['content-disposition'])
+        self.assertTrue(
+            '666,12.12,2012-12-13 00:00:00#,schoolfee,1,my-id,p-item,100,2012,'
+            'paid,2012-12-13 00:00:00#,12.12,r-code,,K1000000,234,123,Anna,,'
+            'Tester,created,2004,2004,,fac1,dep1,CERT1' in self.browser.contents)
         self.assertEqual(len(self.app['datacenter'].running_exports), 1)
         job_id = self.app['datacenter'].running_exports[0][0]
@@ -3608,5 +3635,5 @@
             'zope.mgr - students.browser.FacultiesExportJobContainerJobConfig '
             '- exported: bursary (2004, 100, ug_ft, None, None, None, '
-            '13/12/2012, 14/12/2012), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, schoolfee), job_id=%s'
             % job_id in logcontent
             )
@@ -3669,5 +3696,5 @@
             'zope.mgr - students.browser.FacultyExportJobContainerJobConfig '
             '- exported: students (2004, 100, ug_ft, fac1, None, None, '
-            '13/12/2012, 14/12/2012), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -3721,5 +3748,5 @@
             'zope.mgr - students.browser.DepartmentExportJobContainerJobConfig '
             '- exported: students (2004, 100, ug_ft, None, dep1, None, '
-            '13/12/2012, 14/12/2012), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -3767,5 +3794,6 @@
         self.assertTrue(
             'zope.mgr - students.browser.CertificateExportJobContainerJobConfig '
-            '- exported: students (2004, 100, None, None, None, CERT1, None, None), '
+            '- exported: students '
+            '(2004, 100, None, None, None, CERT1, , , None, None, None), '
             'job_id=%s'
             % job_id in logcontent
