Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12663)
@@ -60,4 +60,5 @@
     )
 from waeup.ikoba.customers.catalog import search
+from waeup.ikoba.customers.workflow import PAYMENT_TRANSITIONS
 
 grok.context(IIkobaObject)
@@ -1446,4 +1447,14 @@
     grok.require('waeup.handleCustomer')
 
+    def submission_allowed(self, action=None):
+        if self.context.state == CREATED and not self.context.fee_based:
+            return True
+        return False
+
+    def payment_expected(self, action=None):
+        if self.context.state == CREATED and self.context.fee_based:
+            return True
+        return False
+
     @property
     def form_fields(self):
@@ -1456,6 +1467,7 @@
         return
 
-    @action(_('Apply now (final submit)'), warning=WARNING_CON)
-    def finalsubmit(self, **data):
+    @action(_('Apply now (final submission)'), warning=WARNING_CON,
+            condition=submission_allowed, style='primary')
+    def submit(self, **data):
         if self.terms_and_conditions and not self.request.form.get(
             'confirm_tc', False):
@@ -1466,8 +1478,45 @@
         msave(self, **data)
         IWorkflowInfo(self.context).fireTransition('submit')
-        self.flash(_('Form has been submitted.'))
+        self.flash(_('Application form has been submitted.'))
         self.redirect(self.url(self.context))
         return
 
+    @action(_('Proceed to checkout'),
+            condition=payment_expected, style='primary')
+    def proceed_checkout(self, **data):
+        if self.terms_and_conditions and not self.request.form.get(
+            'confirm_tc', False):
+            self.flash(_('Please read the terms and conditions and '
+                     'confirm your acceptance of these by ticking '
+                     'the confirmation box.'), type="danger")
+            return
+        msave(self, **data)
+        self.redirect(self.url(self.context, 'select_payment_method'))
+        return
+
+
+class SelectPaymentMethodPage(IkobaEditFormPage):
+    """ Page to to select payment method
+    """
+    grok.context(IContract)
+    grok.name('select_payment_method')
+    grok.require('waeup.handleCustomer')
+    grok.template('selectpaymentmethodpage')
+    pnav = 4
+    label = _('Select payment method')
+
+    def update(self, CANCEL=None):
+        if self.context.state != CREATED or not self.context.fee_based:
+            emit_lock_message(self)
+            return
+        super(SelectPaymentMethodPage, self).update()
+        return
+
+    @action(_('Select payment method and proceed to payment gateway (final submission)'),
+            style='primary', warning=WARNING_CON,)
+    def confirm(self, **data):
+        IWorkflowInfo(self.context).fireTransition('await')
+        self.flash(_('Payment has been initiated.'))
+        return
 
 class ContractTriggerTransitionFormPage(IkobaEditFormPage):
@@ -1493,4 +1542,8 @@
         wf_info = IWorkflowInfo(self.context)
         allowed_transitions = [t for t in wf_info.getManualTransitions()]
+        # Skip payment transitions if total amount is zero
+        if not self.context.fee_based:
+            allowed_transitions = [t for t in allowed_transitions
+                                   if not t[0] in PAYMENT_TRANSITIONS]
         return [dict(name='', title=_('No transition'))] +[
             dict(name=x, title=y) for x, y in allowed_transitions]
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/selectpaymentmethodpage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/selectpaymentmethodpage.pt	(revision 12663)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/selectpaymentmethodpage.pt	(revision 12663)
@@ -0,0 +1,26 @@
+<form action="." tal:attributes="action request/URL" method="post"
+      i18n:domain="waeup.ikoba" enctype="multipart/form-data">
+
+  <table class="form-table">
+    <tbody>
+      <tr>
+        <td class="fieldname" i18n:translate=""></td>
+        <td>
+        </td>
+      </tr>
+      <tr>
+        <td class="fieldname" i18n:translate=""></td>
+        <td>
+
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  <br />
+
+  <div tal:condition="view/availableActions">
+    <input tal:repeat="action view/actions"
+           tal:replace="structure action/render"
+           />
+  </div>
+</form>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/contracts.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/contracts.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/contracts.py	(revision 12663)
@@ -161,4 +161,14 @@
             return
 
+    @property
+    def fee_based(self):
+        if self.product_options:
+            amount = 0
+            for option in self.product_options:
+                amount += option.fee
+            if amount:
+                return True
+        return False
+
 
 class SampleContract(ContractBase):
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12663)
@@ -303,4 +303,5 @@
     valid_from = Attribute('Contract valid from')
     valid_to = Attribute('Contract valid to')
+    fee_based = Attribute('Fee based contract')
 
     contract_id = schema.TextLine(
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/reports/contract_statistics.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/reports/contract_statistics.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/reports/contract_statistics.py	(revision 12663)
@@ -22,5 +22,8 @@
 from zope.interface import implementer, Interface, Attribute
 from waeup.ikoba.interfaces import (
-    IIkobaUtils, CREATED, APPROVED, SUBMITTED, EXPIRED, REJECTED)
+    IIkobaUtils,
+    CREATED, APPROVED,
+    SUBMITTED, EXPIRED,
+    REJECTED, AWAITING)
 from waeup.ikoba.customers.interfaces import ICustomersUtils
 from waeup.ikoba.interfaces import MessageFactory as _
@@ -54,5 +57,5 @@
     types = TYPES.keys()
     type_names = tuple(TYPES.values()) + (u'All',)
-    states = (CREATED, SUBMITTED, APPROVED, EXPIRED, REJECTED)
+    states = (CREATED, AWAITING, SUBMITTED, APPROVED, EXPIRED, REJECTED)
     STATES = getUtility(ICustomersUtils).TRANSLATED_CONTRACT_STATES
     state_names = tuple([STATES[state] for state in states]) + (u'Total',)
@@ -108,5 +111,5 @@
     ('LINEAFTER', (-1,0), (-1,-1), 0.25, colors.black),
     ('LINEBEFORE', (-1,0), (-1,-1), 1.0, colors.black),
-    #('LINEABOVE', (0,-1), (-1,-1), 1.0, colors.black),
+    ('LINEABOVE', (0,-1), (-1,-1), 1.0, colors.black),
     #('LINEABOVE', (0,0), (-1,0), 0.25, colors.black),
     ]
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/reports/tests/test_contract_statistics.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/reports/tests/test_contract_statistics.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/reports/tests/test_contract_statistics.py	(revision 12663)
@@ -17,5 +17,7 @@
     layer = FunctionalLayer
 
-    states = ('created', 'submitted for approval',  'approved', 'expired',
+    states = ('created', 'awaiting payment',
+              'submitted for approval',
+              'approved', 'expired',
               'rejected', 'Total')
 
@@ -34,6 +36,6 @@
             ((u'Sample Contract', u'All'),
              self.states,
-             ((1, 0, 0, 0, 0, 1),
-              (1, 0, 0, 0, 0, 1),))
+             ((1, 0, 0, 0, 0, 0, 1),
+              (1, 0, 0, 0, 0, 0, 1),))
             )
         return
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 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12663)
@@ -1417,11 +1417,12 @@
         # The form is also saved.
         self.browser.getLink("Edit").click()
-        self.browser.getControl("Apply").click()
+        self.browser.getControl("Proceed to checkout").click()
         self.assertTrue('confirm your acceptance of these by ticking' in self.browser.contents)
         self.assertEqual(contract.state, 'created')
         self.browser.getControl(name="confirm_tc").value = True
-        self.browser.getControl("Apply").click()
-        self.assertEqual(contract.state, 'submitted')
-        self.assertTrue('Contract State: submitted for approval' in self.browser.contents)
+        self.browser.getControl("Proceed to checkout").click()
+        self.assertEqual(contract.state, 'created')
+        self.browser.getControl("Select payment method").click()
+        self.assertEqual(contract.state, 'awaiting')
         # Customer can't edit the contract once it has been submitted
         self.browser.open(self.contracts_path + '/%s/edit' % conid)
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_export.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_export.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_export.py	(revision 12663)
@@ -256,9 +256,9 @@
             result,
             'class_name,comment,contract_category,contract_id,document_object,'
-            'history,last_product_id,'
-            'product_object,product_options,state,tc_dict,title,user_id,'
-            'valid_from,valid_to\r\n'
-
-            'SampleContract,,sample,CON1,,[],,,[],,{},,,,\r\n'
+            'fee_based,history,last_product_id,'
+            'product_object,product_options,state,tc_dict,title,'
+            'user_id,valid_from,valid_to\r\n'
+
+            'SampleContract,,sample,CON1,,0,[],,,[],,{},,,,\r\n'
             )
         return
@@ -273,9 +273,9 @@
         self.assertMatches(
             'class_name,comment,contract_category,contract_id,document_object,'
-            'history,last_product_id,'
-            'product_object,product_options,state,tc_dict,title,user_id,'
-            'valid_from,valid_to\r\n'
-
-            'SampleContract,,sample,CON1,DOC1,[u\'2014-12-04 12:10:46 UTC - '
+            'fee_based,history,last_product_id,'
+            'product_object,product_options,state,tc_dict,title,'
+            'user_id,valid_from,valid_to\r\n'
+
+            'SampleContract,,sample,CON1,DOC1,1,[u\'2014-12-04 12:10:46 UTC - '
             'Contract created by system\'],,'
             'SAM,"[(u\'Base Fee\', u\'800.6\', u\'USD\')]",'
@@ -295,9 +295,9 @@
         self.assertMatches(
             'class_name,comment,contract_category,contract_id,document_object,'
-            'history,last_product_id,'
-            'product_object,product_options,state,tc_dict,title,user_id,'
-            'valid_from,valid_to\r\n'
-
-            'SampleContract,,sample,CON1,DOC1,[u\'2014-12-04 12:10:46 UTC - '
+            'fee_based,history,last_product_id,'
+            'product_object,product_options,state,tc_dict,title,'
+            'user_id,valid_from,valid_to\r\n'
+
+            'SampleContract,,sample,CON1,DOC1,1,[u\'2014-12-04 12:10:46 UTC - '
             'Contract created by system\'],,'
             'SAM,"[(u\'Base Fee\', u\'800.6\', u\'USD\')]",'
@@ -317,9 +317,9 @@
         self.assertMatches(
             'class_name,comment,contract_category,contract_id,document_object,'
-            'history,last_product_id,'
-            'product_object,product_options,state,tc_dict,title,user_id,'
-            'valid_from,valid_to\r\n'
-
-            'SampleContract,,sample,CON1,DOC1,[u\'2014-12-04 12:10:46 UTC - '
+            'fee_based,history,last_product_id,'
+            'product_object,product_options,state,tc_dict,title,'
+            'user_id,valid_from,valid_to\r\n'
+
+            'SampleContract,,sample,CON1,DOC1,1,[u\'2014-12-04 12:10:46 UTC - '
             'Contract created by system\'],,'
             'SAM,"[(u\'Base Fee\', u\'800.6\', u\'USD\')]",'
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12663)
@@ -38,5 +38,5 @@
 from waeup.ikoba.interfaces import (
     STARTED, CREATED, REQUESTED, APPROVED, SUBMITTED, VERIFIED, REJECTED,
-    EXPIRED, PROVISIONALLY,
+    EXPIRED, PROVISIONALLY, AWAITING,
     IIkobaUtils, IExtFileStore)
 from waeup.ikoba.customers.interfaces import ICustomersUtils
@@ -308,4 +308,5 @@
     TRANSLATED_CONTRACT_STATES = {
         CREATED: _('created'),
+        AWAITING: _('awaiting payment'),
         SUBMITTED: _('submitted for approval'),
         APPROVED: _('approved'),
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py	(revision 12660)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py	(revision 12663)
@@ -28,5 +28,5 @@
     IObjectHistory, IIkobaWorkflowInfo, IIkobaUtils, IUserAccount,
     STARTED, CREATED, REQUESTED, PROVISIONALLY, APPROVED,
-    SUBMITTED, VERIFIED, REJECTED, EXPIRED)
+    SUBMITTED, VERIFIED, REJECTED, EXPIRED, AWAITING)
 from waeup.ikoba.interfaces import MessageFactory as _
 from waeup.ikoba.workflow import (
@@ -191,4 +191,20 @@
 
     Transition(
+        transition_id = 'await',
+        title = _('Initiate payment'),
+        source = CREATED,
+        condition = NullCondition,
+        msg = _('Payment initiated'),
+        destination = AWAITING),
+
+    Transition(
+        transition_id = 'discard',
+        title = _('Discard payment'),
+        source = AWAITING,
+        condition = NullCondition,
+        msg = _('Payment discarded'),
+        destination = CREATED),
+
+    Transition(
         transition_id = 'submit',
         title = _('Submit for approval'),
@@ -198,4 +214,11 @@
 
     Transition(
+        transition_id = 'confirm',
+        title = _('Confirm payment'),
+        msg = _('Payment and submission confirmed'),
+        source = AWAITING,
+        destination = SUBMITTED),
+
+    Transition(
         transition_id = 'approve',
         title = _('Approve'),
@@ -245,5 +268,8 @@
         source = EXPIRED,
         destination = CREATED),
+
     )
+
+PAYMENT_TRANSITIONS = ['await', 'discard', 'confirm']
 
 contract_workflow = IkobaWorkflow(CONTRACT_TRANSITIONS)
@@ -286,6 +312,6 @@
     history = IObjectHistory(obj)
     history.addMessage(msg)
-    if event.transition.transition_id not in ('create', 'submit') \
-        and obj.customer:
+    if event.transition.transition_id not in (
+        'create', 'submit', 'confirm', 'await') and obj.customer:
         ikoba_utils = getUtility(IIkobaUtils)
         ikoba_utils.sendTransitionInfo(IUserAccount(obj.customer), obj, msg)
