Index: /main/waeup.kofa/trunk/CHANGES.txt
===================================================================
--- /main/waeup.kofa/trunk/CHANGES.txt	(revision 14803)
+++ /main/waeup.kofa/trunk/CHANGES.txt	(revision 14804)
@@ -4,4 +4,7 @@
 1.6.dev0 (unreleased)
 =======================
+
+* Allow `ApplicantOnlinePaymentProcessor` to import records without
+  `p_id` column in create mode.
 
 * Add `waeup.showStudents` permission to `ExportManager` role.
Index: /main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py	(revision 14803)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py	(revision 14804)
@@ -360,12 +360,20 @@
     factory_name = 'waeup.ApplicantOnlinePayment'
 
-    location_fields = ['applicant_id', 'p_id']
+    location_fields = ['applicant_id',]
 
     @property
     def available_fields(self):
         af = sorted(list(set(
-            self.location_fields + getFields(self.iface).keys())))
+            self.location_fields + getFields(self.iface).keys())) +
+            ['p_id',])
         af.remove('display_item')
         return af
+
+    def checkHeaders(self, headerfields, mode='ignore'):
+        super(ApplicantOnlinePaymentProcessor, self).checkHeaders(headerfields)
+        if mode in ('update', 'remove') and not 'p_id' in headerfields:
+            raise FatalCSVError(
+                "Need p_id for import in update and remove modes!")
+        return True
 
     def parentsExist(self, row, site):
Index: /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_payment_data.csv
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_payment_data.csv	(revision 14803)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_payment_data.csv	(revision 14804)
@@ -1,2 +1,3 @@
 applicant_id,p_state,p_category,p_id,p_session,r_amount_approved,amount_auth,creation_date,type
+dp2011_1234,failed,application,,2016,19500.1,10500.1,2011-11-25 20:16:33.757 WAT,online
 dp2011_1234,paid,application,p1266236341955,2015,19500.1,19500.1,2010-11-25 20:16:33.757 WAT,online
Index: /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_batching.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_batching.py	(revision 14803)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_batching.py	(revision 14804)
@@ -530,5 +530,5 @@
         num, num_warns, fin_file, fail_file = self.processor.doImport(
             self.csv_file, PAYMENT_HEADER_FIELDS,'create')
-        self.assertEqual(num_warns,1)
+        self.assertEqual(num_warns,2)
         fail_file = open(fail_file).read()
         self.assertTrue('Payment has already been made' in fail_file)
@@ -538,5 +538,7 @@
         num, num_warns, fin_file, fail_file = self.processor.doImport(
             self.csv_file, PAYMENT_HEADER_FIELDS,'create')
+        # Both records can be imported now.
         self.assertEqual(num_warns,0)
+        # One with imported and known p_id ...
         payment = self.processor.getEntry(dict(applicant_id='dp2011_1234',
             p_id='p1266236341955'), self.app)
@@ -548,4 +550,10 @@
         self.assertEqual(cdate, '2010-11-25 21:16:33')
         self.assertEqual(str(payment.creation_date.tzinfo),'UTC')
+        # ... the other one with generated p_id.
+        p_id_failed = self.applicant2.keys()[1]
+        payment_failed = self.processor.getEntry(dict(applicant_id='dp2011_1234',
+            p_id=p_id_failed), self.app)
+        self.assertEqual(payment_failed.p_state, 'failed')
+        self.assertEqual(payment_failed.amount_auth, 10500.1)
         shutil.rmtree(os.path.dirname(fin_file))
         logcontent = open(self.logfile).read()
@@ -553,6 +561,5 @@
         self.assertTrue(
             'INFO - system - ApplicantOnlinePayment Processor - dp2011_1234 - '
-            'previous update cancelled'
-            in logcontent)
+            'previous update cancelled' in logcontent)
         self.assertTrue(
             'INFO - system - ApplicantOnlinePayment Processor - '
@@ -560,4 +567,10 @@
             'creation_date=2010-11-25 21:16:33.757000+00:00, '
             'r_amount_approved=19500.1, p_category=application, '
-            'amount_auth=19500.1, p_session=2015, p_state=paid'
-            in logcontent)
+            'amount_auth=19500.1, p_session=2015, p_state=paid' in logcontent)
+        self.assertTrue(
+            'INFO - system - ApplicantOnlinePayment Processor - '
+            'sample_payment_data - dp2011_1234 - updated: p_id=%s, '
+            'creation_date=2011-11-25 21:16:33.757000+00:00, '
+            'r_amount_approved=19500.1, p_category=application, '
+            'amount_auth=10500.1, p_session=2016, p_state=failed'
+            % p_id_failed in logcontent)
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py	(revision 14803)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py	(revision 14804)
@@ -748,5 +748,5 @@
 
     The `checkConversion` method checks the format of the payment identifier.
-    In create mode it does also ensures that same p_id does not exist
+    In create mode it does also ensures that same `p_id` does not exist
     elsewhere. It must be portal-wide unique.
 
