Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12770)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12772)
@@ -43,4 +43,5 @@
 from waeup.ikoba.payments.payment import (
     get_payments_from_payer_id,
+    get_payments_from_payable_id,
     find_payable_from_payable_id,
     get_payment_providers
@@ -1732,2 +1733,37 @@
         return search_payments(
             query=self.context.customer_id, searchtype='payer_id')
+
+
+class PDFContractReceiptPage(UtilityView, grok.View):
+    """Deliver pdf file including metadata.
+    """
+    grok.context(IContract)
+    grok.name('contract_payment_receipt.pdf')
+    grok.require('waeup.viewCustomer')
+    prefix = 'form'
+
+    omit_fields = ('suspended', 'sex',
+                   'suspended_comment',)
+
+    @property
+    def form_fields(self):
+        return grok.AutoFields(self.context.form_fields_interface)
+
+    @property
+    def label(self):
+        return 'Payment Receipt: %s' % (
+            self.context.title)
+
+    @property
+    def payment(self):
+        return get_payments_from_payable_id(self.context.contract_id)
+
+    def render(self):
+        customerview = CustomerBasePDFFormPage(self.context.customer,
+            self.request, self.omit_fields)
+        customers_utils = getUtility(ICustomersUtils)
+        return customers_utils.renderPDF(
+            self, 'contract_payment_receipt.pdf',
+            self.context.customer, customerview,
+            omit_fields=self.omit_fields,
+            show_history=False)
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12770)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12772)
@@ -50,4 +50,6 @@
 from waeup.ikoba.products.productoptions import ProductOption
 from waeup.ikoba.customers.interfaces import CurrencyMismatch
+from waeup.ikoba.payments.payment import Payment
+from waeup.ikoba.payments.interfaces import IPayer, IPayable, STATE_PAID
 
 PH_LEN = 15911  # Length of placeholder file
@@ -1291,4 +1293,12 @@
         'Select payment method (final submission)')
 
+    def setup_payment(self):
+        payer = IPayer(self.customer)
+        payable = IPayable(self.contract)
+        self.payment = Payment(payer, payable)
+        self.payment.gateway_service = 'demo_creditcard'
+        self.payment.state = STATE_PAID
+        self.app['payments'][self.payment.payment_id] = self.payment
+
     def add_product_option(self, contract):
         prodoption = ProductOption()
@@ -1565,4 +1575,22 @@
         print "Sample contract_slip.pdf written to %s" % path
 
+    def test_view_receipt(self):
+        self.add_product_option(self.contract)
+        self.setup_payment()
+        IWorkflowState(self.document).setState(SUBMITTED)
+        self.contract.document_object = self.document
+        self.contract.product_object = self.product
+        self.contract.title = u'Contract Title'
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        # Officers can open the receipt
+        self.browser.open(self.customer_path + '/contracts/CON1')
+        self.browser.getLink("Download payment receipt").click()
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertEqual(
+            self.browser.headers['Content-Type'], 'application/pdf')
+        path = os.path.join(samples_dir(), 'contract_payment_receipt.pdf')
+        open(path, 'wb').write(self.browser.contents)
+        print "Sample contract_payment_receipt.pdf written to %s" % path
+
     def test_contract_approval(self):
         # This is not a UI test. It's just a functional test.
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12770)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12772)
@@ -43,6 +43,7 @@
 from waeup.ikoba.browser.interfaces import IPDFCreator
 from waeup.ikoba.browser.pdf import (
-    ENTRY1_STYLE, format_html, NOTE_STYLE, HEADING_STYLE,
+    ENTRY1_STYLE, format_html, NOTE_STYLE, HEADING_STYLE, HEADLINE1_STYLE,
     get_signature_tables, get_qrcode)
+from waeup.ikoba.payments.interfaces import STATE_PAID
 
 RE_CUSTID_NON_NUM = re.compile('[^\d]+')
@@ -384,5 +385,5 @@
         # Insert widgets
         if view.form_fields:
-            if view.__name__ == 'contract_slip.pdf':
+            if view.__name__.startswith('contract'):
                 data_header = trans(_('Contract Data'), portal_language)
                 data.append(Paragraph(data_header, HEADING_STYLE))
@@ -392,4 +393,14 @@
                 separators=separators)
             data.append(table)
+
+        # Insert payment data
+        if getattr(view, 'payment', None) is not None:
+            data_header = trans(_('Payment Data'), portal_language)
+            data.append(Paragraph(data_header, HEADING_STYLE))
+            for payment in getattr(view, 'payment', None):
+                if payment.state != STATE_PAID:
+                    continue
+                data.append(Paragraph('Payment', HEADLINE1_STYLE))
+                # XXX: Collect and render payment data
 
         # Insert scanned docs
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/viewlets.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/viewlets.py	(revision 12770)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/viewlets.py	(revision 12772)
@@ -29,5 +29,6 @@
     ICustomer, ICustomersContainer,
     ICustomerDocumentsContainer, ICustomerDocument,
-    IContractsContainer, IContract, ICustomersUtils)
+    IContractsContainer, IContract, ICustomersUtils,
+    )
 from waeup.ikoba.customers.browser import (
     CustomersContainerPage, CustomersContainerManagePage,
@@ -37,4 +38,6 @@
     ContractManageFormPage,
     ContractOfficialUsePage)
+from waeup.ikoba.payments.payment import get_payments_from_payable_id
+from waeup.ikoba.payments.interfaces import STATE_PAID
 
 grok.context(IIkobaObject)  # Make IIkobaObject the default context
@@ -469,2 +472,20 @@
     target = 'contract_slip.pdf'
 
+class PDFContractReceiptActionButton(ManageActionButton):
+    grok.order(5)
+    grok.context(IContract)
+    grok.view(ContractDisplayFormPage)
+    grok.require('waeup.viewCustomer')
+    icon = 'actionicon_pdf.png'
+    text = _('Download payment receipt')
+    target = 'contract_payment_receipt.pdf'
+
+    @property
+    def target_url(self):
+        payments = get_payments_from_payable_id(self.context.contract_id)
+        if payments is not None:
+            for payment in payments:
+                if payment.state == STATE_PAID:
+                     return self.view.url(self.view.context, self.target)
+        return ''
+       
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/payments/payment.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/payments/payment.py	(revision 12770)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/payments/payment.py	(revision 12772)
@@ -56,4 +56,5 @@
     return None
 
+
 def get_payments_from_payer_id(payer_id):
     """Get payments by payer id.
@@ -64,4 +65,17 @@
     result_set = [x for x in cat.searchResults(
         payer_id=(payer_id, payer_id))]
+    if len(result_set):
+        return result_set
+    return None
+
+
+def get_payments_from_payable_id(payable_id):
+    """Get payments by payer id.
+
+    If no such payment can be found in catalog, return none.
+    """
+    cat = getUtility(ICatalog, name='payments_catalog')
+    result_set = [x for x in cat.searchResults(
+        payable_id=(payable_id, payable_id))]
     if len(result_set):
         return result_set
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/payments/tests/test_payment.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/payments/tests/test_payment.py	(revision 12770)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/payments/tests/test_payment.py	(revision 12772)
@@ -36,5 +36,5 @@
     Payment, get_payment_providers, PaymentItem, format_payment_item_values,
     get_payment, get_payments_from_payer_id, find_payable_from_payable_id,
-    find_payer_from_payer_id, format_amount,
+    find_payer_from_payer_id, get_payments_from_payable_id, format_amount,
     )
 from waeup.ikoba.testing import (FunctionalLayer, FunctionalTestCase)
@@ -169,4 +169,16 @@
         self.assertTrue(result[0] is p1)
         self.assertTrue(get_payments_from_payer_id('not-valid') is None)
+
+    def test_get_payments_from_payable_id(self):
+        # we can lookup payments.
+        self.getRootFolder()['app'] = Company()
+        app = self.getRootFolder()['app']
+        setSite(app)
+        p1 = Payment(FakePayer(), FakePayable())
+        app['payments']['1'] = p1
+        p_id = p1.payment_id
+        result = get_payments_from_payable_id('PAYABLE_01')
+        self.assertTrue(result[0] is p1)
+        self.assertTrue(get_payments_from_payable_id('not-valid') is None)
 
     def test_find_payable_from_payable_id(self):
