source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py @ 12768

Last change on this file since 12768 was 12768, checked in by Henrik Bettermann, 10 years ago

Add constraint to forbid the selection of options with different currencies.

  • Property svn:keywords set to Id
File size: 78.4 KB
Line 
1## $Id: test_browser.py 12768 2015-03-15 13:02:49Z henrik $
2##
3## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Test the customer-related UI components.
20"""
21import shutil
22import tempfile
23import logging
24import base64
25from decimal import Decimal
26from datetime import datetime, timedelta, date
27from StringIO import StringIO
28import os
29import grok
30from zc.async.testing import wait_for_result
31from zope.event import notify
32from zope.component import createObject, queryUtility, getUtility
33from zope.component.hooks import setSite, clearSite
34from zope.schema.interfaces import ConstraintNotSatisfied
35from zope.catalog.interfaces import ICatalog
36from zope.security.interfaces import Unauthorized
37from zope.securitypolicy.interfaces import IPrincipalRoleManager
38from zope.testbrowser.testing import Browser
39from hurry.workflow.interfaces import (
40    IWorkflowInfo, IWorkflowState, InvalidTransitionError)
41from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
42from waeup.ikoba.app import Company
43from waeup.ikoba.interfaces import (
44    IUserAccount, IJobManager, APPROVED, SUBMITTED,
45    IFileStoreNameChooser, NotIdValue)
46from waeup.ikoba.imagestorage import ExtFileStore
47from waeup.ikoba.tests.test_async import FunctionalAsyncTestCase
48from waeup.ikoba.interfaces import VERIFIED
49from waeup.ikoba.browser.tests.test_pdf import samples_dir
50from waeup.ikoba.products.productoptions import ProductOption
51from waeup.ikoba.customers.interfaces import CurrencyMismatch
52
53PH_LEN = 15911  # Length of placeholder file
54
55SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
56SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
57SAMPLE_PDF = os.path.join(os.path.dirname(__file__), 'test_pdf.pdf')
58
59
60def lookup_submit_value(name, value, browser):
61    """Find a button with a certain value."""
62    for num in range(0, 100):
63        try:
64            button = browser.getControl(name=name, index=num)
65            if button.value.endswith(value):
66                return button
67        except IndexError:
68            break
69    return None
70
71
72class CustomersFullSetup(FunctionalTestCase):
73    # A test case that only contains a setup and teardown
74    #
75    # Complete setup for customers handlings is rather complex and
76    # requires lots of things created before we can start. This is a
77    # setup that does all this, creates a company etc.
78    # so that we do not have to bother with that in different
79    # test cases.
80
81    layer = FunctionalLayer
82
83    def setup_customizable_params(self):
84        self._contract_category = u'sample'
85        self._document_factory = 'waeup.CustomerSampleDocument'
86        self._contract_factory = 'waeup.SampleContract'
87        return
88
89    def setUp(self):
90        super(CustomersFullSetup, self).setUp()
91        self.setup_customizable_params()
92        # Setup a sample site for each test
93        app = Company()
94        self.dc_root = tempfile.mkdtemp()
95        app['datacenter'].setStoragePath(self.dc_root)
96
97        # Prepopulate the ZODB...
98        self.getRootFolder()['app'] = app
99        # we add the site immediately after creation to the
100        # ZODB. Catalogs and other local utilities are not setup
101        # before that step.
102        self.app = self.getRootFolder()['app']
103        # Set site here. Some of the following setup code might need
104        # to access grok.getSite() and should get our new app then
105        setSite(app)
106
107        # Add some products
108        self.product = createObject('waeup.Product')
109        self.product.product_id = u'SAM'
110        self.product.title = u'Our Sample Product'
111        self.product.contract_category = self._contract_category
112        self.product.valid_from = date(2014, 12, 4)
113        self.product.tc_dict = {'en': u'Hello world'}
114        prodoption = ProductOption()
115        prodoption.title = u'First option'
116        prodoption.fee = Decimal('99.9')
117        prodoption.currency = 'USD'
118        self.product.options = [prodoption, ]
119        self.app['products'].addProduct(self.product)
120
121        # Add customer with subobjects
122        customer = createObject('waeup.Customer')
123        customer.firstname = u'Anna'
124        customer.lastname = u'Tester'
125        customer.reg_number = u'123'
126        customer.sex = u'm'
127        customer.email = u'aa@aa.ng'
128        customer.phone = u'1234'
129        customer.date_of_birth = date(1981, 2, 4)
130        self.app['customers'].addCustomer(customer)
131        self.customer_id = customer.customer_id
132        self.customer = self.app['customers'][self.customer_id]
133        self.document = createObject(self._document_factory)
134        self.document.title = u'My first document'
135        self.document.document_id = u'DOC1'
136        self.assertRaises(
137            NotIdValue, setattr, self.document, 'document_id',
138            u'id with spaces')
139        self.customer['documents'].addDocument(self.document)
140        self.contract = createObject(self._contract_factory)
141        self.contract.contract_id = u'CON1'
142        self.assertRaises(
143            NotIdValue, setattr, self.contract, 'contract_id',
144            u'id with spaces')
145        self.customer['contracts'].addContract(self.contract)
146
147        # Set password
148        IUserAccount(
149            self.app['customers'][self.customer_id]).setPassword('cpwd')
150
151        self.login_path = 'http://localhost/app/login'
152        self.container_path = 'http://localhost/app/customers'
153        self.manage_container_path = self.container_path + '/@@manage'
154        self.add_customer_path = self.container_path + '/addcustomer'
155        self.customer_path = self.container_path + '/' + self.customer_id
156        self.manage_customer_path = self.customer_path + '/manage_base'
157        self.trigtrans_path = self.customer_path + '/trigtrans'
158        self.history_path = self.customer_path + '/history'
159        self.documents_path = self.customer_path + '/documents'
160        self.contracts_path = self.customer_path + '/contracts'
161
162        # Update the catalog
163        notify(grok.ObjectModifiedEvent(self.customer))
164
165        # Put the prepopulated site into test ZODB and prepare test
166        # browser
167        self.browser = Browser()
168        self.browser.handleErrors = False
169
170    def tearDown(self):
171        super(CustomersFullSetup, self).tearDown()
172        clearSite()
173        shutil.rmtree(self.dc_root)
174
175
176class CustomersContainerUITests(CustomersFullSetup):
177    # Tests for CustomersContainer class views and pages
178
179    layer = FunctionalLayer
180
181    def test_anonymous_access(self):
182        # Anonymous users can't access customers containers
183        self.assertRaises(
184            Unauthorized, self.browser.open, self.container_path)
185        self.assertRaises(
186            Unauthorized, self.browser.open, self.manage_container_path)
187        return
188
189    def test_manage_access(self):
190        # Managers can access the view page of customers
191        # containers and can perform actions
192        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
193        self.browser.open(self.container_path)
194        self.assertEqual(self.browser.headers['Status'], '200 Ok')
195        self.assertEqual(self.browser.url, self.container_path)
196        self.browser.getLink("Manage customer section").click()
197        self.assertEqual(self.browser.headers['Status'], '200 Ok')
198        self.assertEqual(self.browser.url, self.manage_container_path)
199        return
200
201    def test_add_search_delete_customers(self):
202        # Managers can add search and remove customers
203        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
204        self.browser.open(self.manage_container_path)
205        self.browser.getLink("Add customer").click()
206        self.assertEqual(self.browser.headers['Status'], '200 Ok')
207        self.assertEqual(self.browser.url, self.add_customer_path)
208        self.browser.getControl(name="form.firstname").value = 'Bob'
209        self.browser.getControl(name="form.lastname").value = 'Tester'
210        self.browser.getControl(name="form.reg_number").value = '123'
211        self.browser.getControl("Create customer record").click()
212        self.assertTrue('Registration number in use.'
213            in self.browser.contents)
214        self.browser.getControl(name="form.reg_number").value = '1234'
215        self.browser.getControl("Create customer").click()
216        self.assertTrue('Customer created' in self.browser.contents)
217
218        # Registration must be unique
219        self.browser.getLink("Manage").click()
220        self.browser.getControl(name="form.reg_number").value = '123'
221        self.browser.getControl("Save").click()
222        self.assertMatches('...Registration number in use...',
223                           self.browser.contents)
224
225        # We can find a customer with a certain customer_id
226        self.browser.open(self.container_path)
227        self.browser.getControl("Find customer(s)").click()
228        self.assertTrue('Empty search string' in self.browser.contents)
229        self.browser.getControl(name="searchtype").value = ['customer_id']
230        self.browser.getControl(name="searchterm").value = self.customer_id
231        self.browser.getControl("Find customer(s)").click()
232        self.assertTrue('Anna Tester' in self.browser.contents)
233
234        # We can find a customer by searching for all kind of name parts
235        self.browser.open(self.manage_container_path)
236        self.browser.getControl("Find customer(s)").click()
237        self.assertTrue('Empty search string' in self.browser.contents)
238        self.browser.getControl(name="searchtype").value = ['fullname']
239        self.browser.getControl(name="searchterm").value = 'Anna Tester'
240        self.browser.getControl("Find customer(s)").click()
241        self.assertTrue('Anna Tester' in self.browser.contents)
242        self.browser.open(self.manage_container_path)
243        self.browser.getControl(name="searchtype").value = ['fullname']
244        self.browser.getControl(name="searchterm").value = 'Anna'
245        self.browser.getControl("Find customer(s)").click()
246        self.assertTrue('Anna Tester' in self.browser.contents)
247        self.browser.open(self.manage_container_path)
248        self.browser.getControl(name="searchtype").value = ['fullname']
249        self.browser.getControl(name="searchterm").value = 'Tester'
250        self.browser.getControl("Find customer(s)").click()
251        self.assertTrue('Anna Tester' in self.browser.contents)
252        self.browser.open(self.manage_container_path)
253        self.browser.getControl(name="searchtype").value = ['fullname']
254        self.browser.getControl(name="searchterm").value = 'An'
255        self.browser.getControl("Find customer(s)").click()
256        self.assertFalse('Anna Tester' in self.browser.contents)
257        self.browser.open(self.manage_container_path)
258        self.browser.getControl(name="searchtype").value = ['fullname']
259        self.browser.getControl(name="searchterm").value = 'An*'
260        self.browser.getControl("Find customer(s)").click()
261        self.assertTrue('Anna Tester' in self.browser.contents)
262        self.browser.open(self.manage_container_path)
263        self.browser.getControl(name="searchtype").value = ['fullname']
264        self.browser.getControl(name="searchterm").value = 'tester'
265        self.browser.getControl("Find customer(s)").click()
266        self.assertTrue('Anna Tester' in self.browser.contents)
267        self.browser.open(self.manage_container_path)
268        self.browser.getControl(name="searchtype").value = ['fullname']
269        self.browser.getControl(name="searchterm").value = 'Tester Ana'
270        self.browser.getControl("Find customer(s)").click()
271        self.assertFalse('Anna Tester' in self.browser.contents)
272        self.browser.open(self.manage_container_path)
273        self.browser.getControl(name="searchtype").value = ['fullname']
274        self.browser.getControl(name="searchterm").value = 'Tester Anna'
275        self.browser.getControl("Find customer(s)").click()
276        self.assertTrue('Anna Tester' in self.browser.contents)
277        # The old searchterm will be used again
278        self.browser.getControl("Find customer(s)").click()
279        self.assertTrue('Anna Tester' in self.browser.contents)
280
281        # We can find suspended customers
282        self.customer.suspended = True
283        notify(grok.ObjectModifiedEvent(self.customer))
284        self.browser.open(self.manage_container_path)
285        self.browser.getControl(name="searchtype").value = ['suspended']
286        self.browser.getControl("Find customer(s)").click()
287        self.assertTrue('Anna Tester' in self.browser.contents)
288
289        # Removed customers won't be found
290        ctrl = self.browser.getControl(name='entries')
291        ctrl.getControl(value=self.customer_id).selected = True
292        self.browser.getControl("Remove selected", index=0).click()
293        self.assertTrue('Successfully removed' in self.browser.contents)
294        self.browser.getControl(name="searchtype").value = ['customer_id']
295        self.browser.getControl(name="searchterm").value = self.customer_id
296        self.browser.getControl("Find customer(s)").click()
297        self.assertTrue('No customer found' in self.browser.contents)
298        return
299
300
301class OfficerUITests(CustomersFullSetup):
302    # Tests for Customer class views and pages
303
304    def setup_logging(self):
305        # setup a log-handler that catches all fake mailer output
306        self.stream = StringIO()
307        handler = logging.StreamHandler(self.stream)
308        logger = logging.getLogger('test.smtp')
309        logger.addHandler(handler)
310        logger.setLevel(logging.INFO)
311        return
312
313    def get_fake_smtp_output(self):
314        # get output generated by fake mailer
315        self.stream.flush()
316        self.stream.seek(0)
317        return self.stream.read()
318
319    def teardown_logging(self):
320        # remove the log handler for fake mailer output
321        logger = logging.getLogger('test.smtp')
322        handlers = [x for x in logger.handlers]
323        for handler in handlers:
324            logger.removeHandler(handler)
325        return
326
327    def test_basic_auth(self):
328        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
329        self.browser.open('http://localhost/app')
330        self.browser.getLink("Logout").click()
331        self.assertTrue('You have been logged out' in self.browser.contents)
332        # But we are still logged in since we've used basic
333        # authentication here.  Wikipedia says: Existing browsers
334        # retain authentication information until the tab or browser
335        # is closed or the user clears the history.  HTTP does not
336        # provide a method for a server to direct clients to discard
337        # these cached credentials. This means that there is no
338        # effective way for a server to "log out" the user without
339        # closing the browser. This is a significant defect that
340        # requires browser manufacturers to support a "logout" user
341        # interface element ...
342        self.assertTrue('Manager' in self.browser.contents)
343
344    def test_basic_auth_base64(self):
345        auth_token = base64.b64encode('mgr:mgrpw')
346        self.browser.addHeader('Authorization', 'Basic %s' % auth_token)
347        self.browser.open(self.manage_container_path)
348        self.assertEqual(self.browser.headers['Status'], '200 Ok')
349
350    def test_manage_access(self):
351        # Managers can access the pages of customers
352        # and can perform actions
353        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
354        self.browser.open(self.customer_path)
355        self.assertEqual(self.browser.headers['Status'], '200 Ok')
356        self.assertEqual(self.browser.url, self.customer_path)
357        self.browser.getLink("Transition").click()
358        self.assertEqual(self.browser.headers['Status'], '200 Ok')
359        # Managers can trigger transitions
360        self.browser.getControl(name="transition").value = ['start']
361        self.browser.getControl("Apply").click()
362        # Managers can edit base
363        self.browser.open(self.customer_path)
364        self.browser.getLink("Manage").click()
365        self.assertEqual(self.browser.url, self.manage_customer_path)
366        self.assertEqual(self.browser.headers['Status'], '200 Ok')
367        self.browser.getControl(name="form.firstname").value = 'John'
368        self.browser.getControl(name="form.lastname").value = 'Tester'
369        self.browser.getControl(name="form.reg_number").value = '345'
370        self.browser.getControl(name="password").value = 'secret'
371        self.browser.getControl(name="control_password").value = 'secret'
372        self.browser.getControl("Save").click()
373        self.assertMatches('...Form has been saved...',
374                           self.browser.contents)
375
376    def test_manage_contact_customer(self):
377        # Managers can contact customer
378        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
379        self.browser.open(self.customer_path)
380        self.browser.getLink("Send email").click()
381        self.browser.getControl(
382            name="form.subject").value = 'Important subject'
383        self.browser.getControl(name="form.body").value = 'Hello!'
384        self.browser.getControl("Send message now").click()
385        self.assertTrue('Your message has been sent' in self.browser.contents)
386        return
387
388    def test_manage_upload_passport(self):
389        # Managers can upload a file via the CustomerBaseManageFormPage
390        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
391        self.browser.open(self.manage_customer_path)
392        image = open(SAMPLE_IMAGE_BMP, 'rb')
393        ctrl = self.browser.getControl(name='passportmanageupload')
394        file_ctrl = ctrl.mech_control
395        file_ctrl.add_file(image, filename='my_photo.bmp')
396        self.browser.getControl(
397            name='upload_passportmanageupload').click()
398        self.assertTrue('jpg file format expected'
399            in self.browser.contents)
400        ctrl = self.browser.getControl(name='passportmanageupload')
401        file_ctrl = ctrl.mech_control
402        image = open(SAMPLE_IMAGE, 'rb')
403        file_ctrl.add_file(image, filename='my_photo.jpg')
404        self.browser.getControl(
405            name='upload_passportmanageupload').click()
406        self.assertTrue(
407            'src="http://localhost/app/customers/K1000000/passport.jpg"'
408            in self.browser.contents)
409        # We remove the passport file again
410        self.browser.open(self.manage_customer_path)
411        self.browser.getControl('Delete').click()
412        self.assertTrue('passport.jpg deleted' in self.browser.contents)
413
414    def test_manage_workflow_send_transition_information(self):
415        # Managers can pass through the whole workflow
416        config = grok.getSite()['configuration']
417        config.email_notification = True
418        self.setup_logging()
419        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
420        self.customer = self.app['customers'][self.customer_id]
421        self.browser.open(self.trigtrans_path)
422        self.browser.getControl(name="transition").value = ['start']
423        self.browser.getControl("Apply").click()
424        self.browser.open(self.trigtrans_path)
425        self.browser.getControl(name="transition").value = ['request']
426        self.browser.getControl("Apply").click()
427        self.browser.open(self.trigtrans_path)
428        self.browser.getControl(name="transition").value = ['reject']
429        self.browser.getControl("Apply").click()
430        # The customer is being notified by email after rejection
431        expected = [
432            u'Sending email from no-reply@waeup.org to aa@aa.ng:',
433            u'Message:', u'msg: MIME-Version: 1.0',
434            u'msg: Content-Type: text/plain; charset="us-ascii"',
435            u'msg: Content-Transfer-Encoding: 7bit',
436            u'msg: From: Administrator <no-reply@waeup.org>',
437            u'msg: To: Anna Tester <aa@aa.ng>',
438            u'msg: Reply-To: Administrator <contact@waeup.org>',
439            u'msg: Subject: Ikoba status change information',
440            u'msg: ',
441            u'msg: Dear Anna Tester,',
442            u'msg: ',
443            u'msg: The status of the following object has been changed:',
444            u'msg: ', u'msg: Object Id: K1000000',
445            u'msg: Title: Anna Tester',
446            u'msg: Transition: customer registration rejected',
447            u'msg: New state: started',
448            u'msg: ',
449            u'msg: Regards,',
450            u'msg: ',
451            u'msg: Manager',
452            u'msg: ',
453            u'msg: --',
454            u'msg: Sample Company',
455            u'msg: ',
456            u'']
457        self.assertEqual(expected, self.get_fake_smtp_output().split('\n'))
458        self.browser.open(self.trigtrans_path)
459        self.browser.getControl(name="transition").value = ['request']
460        self.browser.getControl("Apply").click()
461        self.browser.open(self.trigtrans_path)
462        self.browser.getControl(name="transition").value = [
463            'approve_provisionally']
464        self.browser.getControl("Apply").click()
465        self.browser.open(self.trigtrans_path)
466        self.browser.getControl(name="transition").value = ['approve_finally']
467        self.browser.getControl("Apply").click()
468        self.browser.open(self.trigtrans_path)
469        self.browser.getControl(name="transition").value = ['reset1']
470        self.browser.getControl("Apply").click()
471        self.teardown_logging()
472        return
473
474    def test_manage_import(self):
475        # Managers can import customer data files
476        datacenter_path = 'http://localhost/app/datacenter'
477        # Prepare a csv file for customers
478        open('customers.csv', 'wb').write(
479"""firstname,lastname,reg_number,date_of_birth,email,phone,sex,password
480Aaren,Pieri,1,1990-01-02,bb@aa.ng,1234,m,mypwd1
481Claus,Finau,2,1990-01-03,cc@aa.ng,1234,m,mypwd1
482Brit,Berson,2,1990-01-04,dd@aa.ng,1234,m,mypwd1
483""")
484        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
485        self.browser.open(datacenter_path)
486        self.browser.getLink('Upload data').click()
487        filecontents = StringIO(open('customers.csv', 'rb').read())
488        filewidget = self.browser.getControl(name='uploadfile:file')
489        filewidget.add_file(filecontents, 'text/plain', 'customers.csv')
490        self.browser.getControl(name='SUBMIT').click()
491        self.browser.getLink('Process data').click()
492        button = lookup_submit_value(
493            'select', 'customers_zope.mgr.csv', self.browser)
494        button.click()
495        importerselect = self.browser.getControl(name='importer')
496        modeselect = self.browser.getControl(name='mode')
497        importerselect.getControl('Customer Processor').selected = True
498        modeselect.getControl(value='create').selected = True
499        self.browser.getControl('Proceed to step 3').click()
500        self.assertTrue('Header fields OK' in self.browser.contents)
501        self.browser.getControl('Perform import').click()
502        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
503        self.assertTrue(
504            'Successfully processed 2 rows' in self.browser.contents)
505        self.assertTrue('Batch processing finished' in self.browser.contents)
506
507        # The customers are properly indexed and we can
508        # thus find a customer in  the department
509        self.browser.open(self.manage_container_path)
510        # We can search for a new customer by name ...
511        self.browser.getControl(name="searchtype").value = ['fullname']
512        self.browser.getControl(name="searchterm").value = 'Claus'
513        self.browser.getControl("Find customer(s)").click()
514        self.assertTrue('Claus Finau' in self.browser.contents)
515        # ... and check if the imported password has been properly set
516        ctrl = self.browser.getControl(name='entries')
517        value = ctrl.options[0]
518        claus = self.app['customers'][value]
519        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
520        return
521
522    def test_activate_deactivate_buttons(self):
523        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
524        self.browser.open(self.customer_path)
525        self.browser.getLink("Deactivate").click()
526        self.assertTrue(
527            'Customer account has been deactivated.' in self.browser.contents)
528        self.assertTrue(
529            'Base Data (account deactivated)' in self.browser.contents)
530        self.assertTrue(self.customer.suspended)
531        self.browser.getLink("Activate").click()
532        self.assertTrue(
533            'Customer account has been activated.' in self.browser.contents)
534        self.assertFalse(
535            'Base Data (account deactivated)' in self.browser.contents)
536        self.assertFalse(self.customer.suspended)
537        # History messages have been added ...
538        self.browser.getLink("History").click()
539        self.assertTrue(
540            'Customer account deactivated by Manager<br />'
541            in self.browser.contents)
542        self.assertTrue(
543            'Customer account activated by Manager<br />'
544            in self.browser.contents)
545        # ... and actions have been logged.
546        logfile = os.path.join(
547            self.app['datacenter'].storage, 'logs', 'customers.log')
548        logcontent = open(logfile).read()
549        self.assertTrue(
550            'zope.mgr - customers.browser.CustomerDeactivatePage - '
551            'K1000000 - account deactivated' in logcontent)
552        self.assertTrue(
553            'zope.mgr - customers.browser.CustomerActivatePage - '
554            'K1000000 - account activated' in logcontent)
555
556    def test_login_as_customer(self):
557        # CustomerImpersonators can login as customer
558        self.app['users'].addUser('mrofficer', 'mrofficersecret')
559        self.app['users']['mrofficer'].email = 'mrofficer@foo.ng'
560        self.app['users']['mrofficer'].title = 'Harry Actor'
561        prmglobal = IPrincipalRoleManager(self.app)
562        prmglobal.assignRoleToPrincipal(
563            'waeup.CustomerImpersonator', 'mrofficer')
564        prmglobal.assignRoleToPrincipal('waeup.CustomersManager', 'mrofficer')
565        self.assertEqual(self.customer.state, 'created')
566        # Login as customer impersonator
567        self.browser.open(self.login_path)
568        self.browser.getControl(name="form.login").value = 'mrofficer'
569        self.browser.getControl(name="form.password").value = 'mrofficersecret'
570        self.browser.getControl("Login").click()
571        self.assertMatches('...You logged in...', self.browser.contents)
572        self.browser.open(self.customer_path)
573        self.browser.getLink("Login as").click()
574        self.browser.getControl("Set password now").click()
575        temp_password = self.browser.getControl(name='form.password').value
576        self.browser.getControl("Login now").click()
577        self.assertMatches(
578            '...You successfully logged in as...', self.browser.contents)
579        # Status has changed
580        self.assertEqual(self.customer.state, 'started')
581        # We are logged in as customer and can see the 'My Data' tab
582        self.assertMatches(
583            '...<a href="#" class="dropdown-toggle"'
584            ' data-toggle="dropdown">...',
585            self.browser.contents)
586        self.assertMatches(
587            '...My Data...',
588            self.browser.contents)
589        self.browser.getLink("Logout").click()
590        # The customer can't login with the original password ...
591        self.browser.open(self.login_path)
592        self.browser.getControl(name="form.login").value = self.customer_id
593        self.browser.getControl(name="form.password").value = 'cpwd'
594        self.browser.getControl("Login").click()
595        self.assertMatches(
596            '...Your account has been temporarily deactivated...',
597            self.browser.contents)
598        # ... but with the temporary password
599        self.browser.open(self.login_path)
600        self.browser.getControl(name="form.login").value = self.customer_id
601        self.browser.getControl(name="form.password").value = temp_password
602        self.browser.getControl("Login").click()
603        self.assertMatches('...You logged in...', self.browser.contents)
604        # Creation of temp_password is properly logged
605        logfile = os.path.join(
606            self.app['datacenter'].storage, 'logs', 'customers.log')
607        logcontent = open(logfile).read()
608        self.assertTrue(
609            'mrofficer - customers.browser.LoginAsCustomerStep1 - K1000000 - '
610            'temp_password generated: %s' % temp_password in logcontent)
611
612
613class CustomerUITests(CustomersFullSetup):
614    # Tests for Customer class views and pages
615
616    def test_customer_login_with_email(self):
617        self.assertEqual(self.customer.state, 'created')
618        self.browser.open(self.login_path)
619        self.browser.getControl(name="form.login").value = self.customer.email
620        self.browser.getControl(name="form.password").value = 'cpwd'
621        self.browser.getControl("Login").click()
622        self.assertEqual(self.browser.url, self.customer_path)
623        self.assertTrue('You logged in' in self.browser.contents)
624        # Status has changed
625        self.assertEqual(self.customer.state, 'started')
626        return
627
628    def test_customer_change_password(self):
629        # Customers can change the password
630        self.assertEqual(self.customer.state, 'created')
631        self.customer.personal_updated = datetime.utcnow()
632        self.browser.open(self.login_path)
633        self.browser.getControl(name="form.login").value = self.customer_id
634        self.browser.getControl(name="form.password").value = 'cpwd'
635        self.browser.getControl("Login").click()
636        self.assertEqual(self.browser.url, self.customer_path)
637        self.assertTrue('You logged in' in self.browser.contents)
638        # Status has changed
639        self.assertEqual(self.customer.state, 'started')
640        # Change password
641        self.browser.getLink("Change password").click()
642        self.browser.getControl(name="change_password").value = 'pw'
643        self.browser.getControl(
644            name="change_password_repeat").value = 'pw'
645        self.browser.getControl("Save").click()
646        self.assertTrue('Password must have at least' in self.browser.contents)
647        self.browser.getControl(name="change_password").value = 'new_password'
648        self.browser.getControl(
649            name="change_password_repeat").value = 'new_passssword'
650        self.browser.getControl("Save").click()
651        self.assertTrue('Passwords do not match' in self.browser.contents)
652        self.browser.getControl(name="change_password").value = 'new_password'
653        self.browser.getControl(
654            name="change_password_repeat").value = 'new_password'
655        self.browser.getControl("Save").click()
656        self.assertTrue('Password changed' in self.browser.contents)
657        # We are still logged in. Changing the password hasn't thrown us out.
658        self.browser.getLink("Base Data").click()
659        self.assertEqual(self.browser.url, self.customer_path)
660        # We can logout
661        self.browser.getLink("Logout").click()
662        self.assertTrue('You have been logged out' in self.browser.contents)
663        self.assertEqual(self.browser.url, 'http://localhost/app/index')
664        # We can login again with the new password
665        self.browser.getLink("Login").click()
666        self.browser.open(self.login_path)
667        self.browser.getControl(name="form.login").value = self.customer_id
668        self.browser.getControl(name="form.password").value = 'new_password'
669        self.browser.getControl("Login").click()
670        self.assertEqual(self.browser.url, self.customer_path)
671        self.assertTrue('You logged in' in self.browser.contents)
672        return
673
674    def test_customer_edit_upload_upload_and_request(self):
675        # Customer cant login if their password is not set
676        self.browser.open(self.login_path)
677        self.browser.getControl(name="form.login").value = self.customer_id
678        self.browser.getControl(name="form.password").value = 'cpwd'
679        self.browser.getControl("Login").click()
680        self.assertMatches(
681            '...You logged in...', self.browser.contents)
682        self.browser.getLink("Edit").click()
683        self.browser.getControl(name="form.email").value = 'new_email@aa.ng'
684        self.browser.getControl("Save", index=0).click()
685        self.assertMatches('...Form has been saved...',
686                           self.browser.contents)
687        self.browser.getControl("Save and request registration").click()
688        self.assertMatches('...Passport picture is missing...',
689                           self.browser.contents)
690        self.assertEqual(self.customer.state, 'started')
691        # Customer must upload a passport picture. We are already on
692        # the upload page.
693        ctrl = self.browser.getControl(name='passporteditupload')
694        file_obj = open(SAMPLE_IMAGE, 'rb')
695        file_ctrl = ctrl.mech_control
696        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
697        self.browser.getControl(
698            name='upload_passporteditupload').click()
699        self.assertTrue(
700            'src="http://localhost/app/customers/K1000000/passport.jpg"'
701            in self.browser.contents)
702        self.browser.getControl(name="CANCEL").click()
703        self.assertEqual(self.browser.url, self.customer_path)
704        self.browser.getLink("Edit").click()
705        self.browser.getControl("Save and request registration").click()
706        self.assertMatches('...Registration form has been submitted...',
707                           self.browser.contents)
708        self.assertEqual(self.customer.state, 'requested')
709        # Customer can view history
710        self.browser.getLink("History").click()
711        self.assertMatches('...Customer created by system...',
712            self.browser.contents)
713
714    def test_customer_login(self):
715        # Customer cant login if their password is not set
716        self.customer.password = None
717        self.browser.open(self.login_path)
718        self.browser.getControl(name="form.login").value = self.customer_id
719        self.browser.getControl(name="form.password").value = 'cpwd'
720        self.browser.getControl("Login").click()
721        self.assertTrue(
722            'You entered invalid credentials.' in self.browser.contents)
723        # We set the password again
724        IUserAccount(
725            self.app['customers'][self.customer_id]).setPassword('cpwd')
726        # Customers can't login if their account is suspended/deactivated
727        self.customer.suspended = True
728        self.browser.open(self.login_path)
729        self.browser.getControl(name="form.login").value = self.customer_id
730        self.browser.getControl(name="form.password").value = 'cpwd'
731        self.browser.getControl("Login").click()
732        self.assertMatches(
733            '...<div class="alert alert-warning">'
734            'Your account has been deactivated.</div>...',
735            self.browser.contents)
736        # If suspended_comment is set this message will be flashed instead
737        self.customer.suspended_comment = u'Aetsch baetsch!'
738        self.browser.getControl(name="form.login").value = self.customer_id
739        self.browser.getControl(name="form.password").value = 'cpwd'
740        self.browser.getControl("Login").click()
741        self.assertMatches(
742            '...<div class="alert alert-warning">Aetsch baetsch!</div>...',
743            self.browser.contents)
744        self.customer.suspended = False
745        # Customers can't login if a temporary password has been set and
746        # is not expired
747        self.app['customers'][self.customer_id].setTempPassword(
748            'anybody', 'temp_cpwd')
749        self.browser.open(self.login_path)
750        self.browser.getControl(name="form.login").value = self.customer_id
751        self.browser.getControl(name="form.password").value = 'cpwd'
752        self.browser.getControl("Login").click()
753        self.assertMatches(
754            '...Your account has been temporarily deactivated...',
755            self.browser.contents)
756        # The customer can login with the temporary password
757        self.browser.open(self.login_path)
758        self.browser.getControl(name="form.login").value = self.customer_id
759        self.browser.getControl(name="form.password").value = 'temp_cpwd'
760        self.browser.getControl("Login").click()
761        self.assertMatches(
762            '...You logged in...', self.browser.contents)
763        # Customer can view the base data
764        self.browser.open(self.customer_path)
765        self.assertEqual(self.browser.headers['Status'], '200 Ok')
766        self.assertEqual(self.browser.url, self.customer_path)
767        # When the password expires ...
768        delta = timedelta(minutes=11)
769        self.app['customers'][self.customer_id].temp_password[
770            'timestamp'] = datetime.utcnow() - delta
771        self.app['customers'][self.customer_id]._p_changed = True
772        # ... the customer will be automatically logged out
773        self.assertRaises(
774            Unauthorized, self.browser.open, self.customer_path)
775        # Then the customer can login with the original password
776        self.browser.open(self.login_path)
777        self.browser.getControl(name="form.login").value = self.customer_id
778        self.browser.getControl(name="form.password").value = 'cpwd'
779        self.browser.getControl("Login").click()
780        self.assertMatches(
781            '...You logged in...', self.browser.contents)
782
783    def test_change_password_request(self):
784        self.browser.open('http://localhost/app/changepw')
785        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
786        self.browser.getControl("Send login credentials").click()
787        self.assertTrue('An email with' in self.browser.contents)
788
789
790class CustomerRegistrationTests(CustomersFullSetup):
791    # Tests for customer registration
792
793    layer = FunctionalLayer
794
795    def test_request_pw(self):
796        # Customer with wrong number can't be found.
797        self.browser.open('http://localhost/app/requestpw')
798        self.browser.getControl(name="form.firstname").value = 'Anna'
799        self.browser.getControl(name="form.number").value = 'anynumber'
800        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
801        self.browser.getControl("Send login credentials").click()
802        self.assertTrue('No customer found.'
803            in self.browser.contents)
804        # Anonymous is not informed that firstname verification failed.
805        # It seems that the record doesn't exist.
806        self.browser.open('http://localhost/app/requestpw')
807        self.browser.getControl(name="form.firstname").value = 'Johnny'
808        self.browser.getControl(name="form.number").value = '123'
809        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
810        self.browser.getControl("Send login credentials").click()
811        self.assertTrue('No customer found.'
812            in self.browser.contents)
813        # Even with the correct firstname we can't register if a
814        # password has been set and used.
815        self.browser.getControl(name="form.firstname").value = 'Anna'
816        self.browser.getControl(name="form.number").value = '123'
817        self.browser.getControl("Send login credentials").click()
818        self.assertTrue('Your password has already been set and used.'
819            in self.browser.contents)
820        self.browser.open('http://localhost/app/requestpw')
821        self.app['customers'][self.customer_id].password = None
822        # The firstname field, used for verification, is not case-sensitive.
823        self.browser.getControl(name="form.firstname").value = 'aNNa'
824        self.browser.getControl(name="form.number").value = '123'
825        self.browser.getControl(name="form.email").value = 'new@yy.zz'
826        self.browser.getControl("Send login credentials").click()
827        # Yeah, we succeded ...
828        self.assertTrue('Your request was successful.'
829            in self.browser.contents)
830        # ... and  customer can be found in the catalog via the email address
831        cat = queryUtility(ICatalog, name='customers_catalog')
832        results = list(
833            cat.searchResults(
834            email=('new@yy.zz', 'new@yy.zz')))
835        self.assertEqual(self.customer, results[0])
836        logfile = os.path.join(
837            self.app['datacenter'].storage, 'logs', 'main.log')
838        logcontent = open(logfile).read()
839        self.assertTrue(
840            'zope.anybody - customers.browser.CustomerRequestPasswordPage - '
841            '123 (K1000000) - new@yy.zz' in logcontent)
842        return
843
844    def test_create_account(self):
845        self.browser.open('http://localhost/app/createaccount')
846        self.browser.getControl(name="form.firstname").value = 'Ruben'
847        self.browser.getControl(name="form.lastname").value = 'Gonzales'
848        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
849        self.browser.getControl("Send login credentials").click()
850        # Email address exists.
851        self.assertTrue('Email address in use.' in self.browser.contents)
852        self.browser.getControl(name="form.email").value = 'newcustomer@xx.zz'
853        self.browser.getControl("Send login credentials").click()
854        self.assertTrue(
855            'Your request was successful.' in self.browser.contents)
856        # Customer can be found in the catalog via the email address
857        cat = queryUtility(ICatalog, name='customers_catalog')
858        results = list(
859            cat.searchResults(
860            email=('newcustomer@xx.zz', 'newcustomer@xx.zz')))
861        self.assertEqual(self.app['customers']['K1000001'], results[0])
862        self.assertEqual(self.app['customers']['K1000001'].firstname, 'Ruben')
863        self.assertEqual(
864            self.app['customers']['K1000001'].lastname, 'Gonzales')
865        logfile = os.path.join(
866            self.app['datacenter'].storage, 'logs', 'main.log')
867        logcontent = open(logfile).read()
868        self.assertTrue(
869            'zope.anybody - customers.browser.CustomerCreateAccountPage - '
870            'K1000001 - newcustomer@xx.zz' in logcontent)
871        return
872
873
874class CustomerDataExportTests(CustomersFullSetup, FunctionalAsyncTestCase):
875    # Tests for CustomersContainer class views and pages
876
877    layer = FunctionalLayer
878
879    def wait_for_export_job_completed(self):
880        # helper function waiting until the current export job is completed
881        manager = getUtility(IJobManager)
882        job_id = self.app['datacenter'].running_exports[0][0]
883        job = manager.get(job_id)
884        wait_for_result(job)
885        return job_id
886
887    def test_datacenter_export(self):
888        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
889        self.browser.open('http://localhost/app/datacenter/@@export')
890        self.browser.getControl(name="exporter").value = ['customers']
891        self.browser.getControl("Create CSV file").click()
892
893        # When the job is finished and we reload the page...
894        job_id = self.wait_for_export_job_completed()
895        # ... the csv file can be downloaded ...
896        self.browser.open('http://localhost/app/datacenter/@@export')
897        self.browser.getLink("Download").click()
898        self.assertEqual(self.browser.headers['content-type'],
899            'text/csv; charset=UTF-8')
900        self.assertTrue(
901            'filename="WAeUP.Ikoba_customers_%s.csv' % job_id in
902            self.browser.headers['content-disposition'])
903        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
904        job_id = self.app['datacenter'].running_exports[0][0]
905        # ... and discarded
906        self.browser.open('http://localhost/app/datacenter/@@export')
907        self.browser.getControl("Discard").click()
908        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
909        # Creation, downloading and discarding is logged
910        logfile = os.path.join(
911            self.app['datacenter'].storage, 'logs', 'datacenter.log')
912        logcontent = open(logfile).read()
913        self.assertTrue(
914            'zope.mgr - browser.pages.ExportCSVPage - exported: '
915            'customers, job_id=%s'
916            % job_id in logcontent
917            )
918        self.assertTrue(
919            'zope.mgr - browser.pages.ExportCSVView - downloaded: '
920            'WAeUP.Ikoba_customers_%s.csv, job_id=%s'
921            % (job_id, job_id) in logcontent
922            )
923        self.assertTrue(
924            'zope.mgr - browser.pages.ExportCSVPage - discarded: '
925            'job_id=%s' % job_id in logcontent
926            )
927
928
929class DocumentUITests(CustomersFullSetup):
930    # Tests for customer document related views and pages
931
932    def test_manage_document(self):
933        # Managers can access the pages of customer documentsconter
934        # and can perform actions
935        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
936        self.browser.open(self.customer_path)
937        self.assertEqual(self.browser.headers['Status'], '200 Ok')
938        self.assertEqual(self.browser.url, self.customer_path)
939        self.browser.open(self.customer_path)
940        self.browser.getLink("Documents", index=1).click()
941        self.browser.getControl("Add document").click()
942        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
943        self.browser.getControl(name="form.title").value = 'My PDF Document'
944        self.browser.getControl("Add document").click()
945        self.assertTrue('PDF Document added.' in self.browser.contents)
946        docid = [i for i in self.customer['documents'].keys()
947                 if len(i) > 10][0]
948        document = self.customer['documents'][docid]
949
950        # Document can be edited
951        self.browser.getLink(docid[:9]).click()
952        self.browser.getLink("Manage").click()
953        self.browser.getControl(name="form.title").value = 'My second doc'
954        self.browser.getControl("Save").click()
955        self.assertTrue('Form has been saved.' in self.browser.contents)
956        self.browser.getLink("View").click()
957        self.assertEqual(self.browser.url,
958            self.documents_path + '/' + docid + '/index')
959
960        # Transitions can be performed
961        self.browser.getLink("Transition").click()
962        self.browser.getControl(name="transition").value = ['submit']
963        self.browser.getControl("Apply").click()
964        self.browser.getLink("Transition").click()
965        # Document can only be verified if customer is approved
966        self.browser.getControl(name="transition").value = ['verify']
967        self.browser.getControl("Apply").click()
968        self.assertTrue(
969            'Customer has not yet been approved' in self.browser.contents)
970        IWorkflowState(self.customer).setState(APPROVED)
971        # Document can only be verified if files have been uploaded before
972        self.browser.getLink("Transition").click()
973        self.browser.getControl(name="transition").value = ['verify']
974        self.browser.getControl("Apply").click()
975        self.assertTrue('No file uploaded' in self.browser.contents)
976        self.assertEqual(document.state, 'submitted')
977        # We set state here manually (verification is tested in
978        # test_verify_document)
979        IWorkflowState(document).setState(VERIFIED)
980
981        # Manage button and form is no longer available
982        self.browser.open(self.documents_path + '/' + docid + '/index')
983        self.assertFalse(
984            'href="http://localhost/app/customers/K1000000/'
985            'documents/%s/manage"'
986            % docid in self.browser.contents)
987        self.browser.open(self.documents_path + '/' + docid + '/manage')
988        self.assertTrue(
989            'The requested form is locked (read-only)'
990            in self.browser.contents)
991
992        # Documents can be removed
993        self.browser.getLink("Documents", index=1).click()
994        ctrl = self.browser.getControl(name='val_id')
995        ctrl.getControl(value=document.document_id).selected = True
996        self.browser.getControl("Remove selected", index=0).click()
997        self.assertTrue('Successfully removed' in self.browser.contents)
998
999        # All actions are being logged
1000        logfile = os.path.join(
1001            self.app['datacenter'].storage, 'logs', 'customers.log')
1002        logcontent = open(logfile).read()
1003
1004        self.assertTrue(
1005            'INFO - system - K1000000 - DOC1 - Document created'
1006            in logcontent)
1007        self.assertTrue(
1008            'INFO - zope.mgr - customers.browser.DocumentAddFormPage '
1009            '- K1000000 - added: PDF Document %s'
1010            % document.document_id in logcontent)
1011        self.assertTrue(
1012            'INFO - zope.mgr - customers.browser.DocumentManageFormPage '
1013            '- K1000000 - %s - saved: title' % docid
1014            in logcontent)
1015        self.assertTrue(
1016            'INFO - zope.mgr - K1000000 - %s - Submitted for verification'
1017            % docid in logcontent)
1018        self.assertTrue(
1019            'INFO - zope.mgr - customers.browser.DocumentsManageFormPage '
1020            '- K1000000 - removed: %s' % docid
1021            in logcontent)
1022
1023    def test_edit_sample_document(self):
1024        # Customers can manage documents under certain conditions
1025        self.browser.open(self.login_path)
1026        self.browser.getControl(name="form.login").value = self.customer_id
1027        self.browser.getControl(name="form.password").value = 'cpwd'
1028        self.browser.getControl("Login").click()
1029        self.assertMatches(
1030            '...You logged in...', self.browser.contents)
1031        self.browser.getLink("Documents").click()
1032        self.browser.getControl("Add document").click()
1033        self.assertTrue(
1034            'The requested form is locked' in self.browser.contents)
1035        # Customer is in wrong state
1036        IWorkflowState(self.customer).setState(APPROVED)
1037        self.browser.getControl("Add document").click()
1038        self.browser.getControl(name="doctype").value = [
1039            'CustomerSampleDocument']
1040        self.browser.getControl(name="form.title").value = 'My Sample Document'
1041        self.browser.getControl("Add document").click()
1042        self.assertTrue('Sample Document added.' in self.browser.contents)
1043        docid = [i for i in self.customer['documents'].keys()
1044                 if len(i) > 10][0]
1045        document = self.customer['documents'][docid]
1046        self.browser.getControl(name="form.title").value = 'My second doc'
1047        self.browser.getControl("Save").click()
1048        self.assertEqual(document.title, 'My second doc')
1049        self.assertTrue('Form has been saved.' in self.browser.contents)
1050        self.browser.getLink("View").click()
1051        self.assertEqual(
1052            self.browser.url, self.documents_path + '/%s/index' % docid)
1053        # Customer can upload a document.
1054        self.browser.getLink("Edit").click()
1055        ctrl = self.browser.getControl(name='samplescaneditupload')
1056        file_obj = open(SAMPLE_IMAGE, 'rb')
1057        file_ctrl = ctrl.mech_control
1058        file_ctrl.add_file(file_obj, filename='my_document.jpg')
1059        self.browser.getControl(
1060            name='upload_samplescaneditupload').click()
1061        self.assertTrue(
1062            'href="http://localhost/app/customers/K1000000/'
1063            'documents/%s/sample"'
1064            % docid in self.browser.contents)
1065        # Customer can submit the form. The form is also saved.
1066        self.browser.getControl(name="form.title").value = 'My third doc'
1067        self.browser.getControl("Final Submit").click()
1068        self.assertEqual(document.title, 'My third doc')
1069        self.assertEqual(document.state, 'submitted')
1070        self.assertTrue(
1071            'Document State: submitted for verification'
1072            in self.browser.contents)
1073        # Customer can't edit the document once it has been submitted
1074        self.browser.open(self.documents_path + '/%s/edit' % docid)
1075        self.assertTrue(
1076            'The requested form is locked' in self.browser.contents)
1077
1078    def test_manage_upload_sample_file(self):
1079        # Managers can upload a file via the DocumentManageFormPage
1080        # The image is stored even if form has errors
1081        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1082        self.browser.open(self.customer_path + '/documents/DOC1/manage')
1083        # Create a pseudo image file and select it to be uploaded
1084        image = open(SAMPLE_IMAGE, 'rb')
1085        ctrl = self.browser.getControl(name='samplescanmanageupload')
1086        file_ctrl = ctrl.mech_control
1087        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1088        # The Save action does not upload files
1089        self.browser.getControl("Save").click()  # submit form
1090        self.assertFalse(
1091            'href="http://localhost/app/customers/K1000000/'
1092            'documents/DOC1/sample"'
1093            in self.browser.contents)
1094        # ... but the correct upload submit button does
1095        image = open(SAMPLE_IMAGE)
1096        ctrl = self.browser.getControl(name='samplescanmanageupload')
1097        file_ctrl = ctrl.mech_control
1098        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1099        self.browser.getControl(
1100            name='upload_samplescanmanageupload').click()
1101        self.assertTrue(
1102            'href="http://localhost/app/customers/K1000000/'
1103            'documents/DOC1/sample"'
1104            in self.browser.contents)
1105        # Browsing the link shows a real image
1106        self.browser.open('sample')
1107        self.assertEqual(
1108            self.browser.headers['content-type'], 'image/jpeg')
1109        self.assertEqual(len(self.browser.contents), 2787)
1110        # We can't reupload a file. The existing file must be deleted first.
1111        self.browser.open(self.customer_path + '/documents/DOC1/manage')
1112        self.assertFalse(
1113            'upload_samplescanmanageupload' in self.browser.contents)
1114        # File must be deleted first
1115        self.browser.getControl(name='delete_samplescanmanageupload').click()
1116        self.assertTrue(
1117            'sample deleted' in self.browser.contents)
1118        # Uploading a file which is bigger than 150k will raise an error
1119        big_image = StringIO(open(SAMPLE_IMAGE, 'rb').read() * 75)
1120        ctrl = self.browser.getControl(name='samplescanmanageupload')
1121        file_ctrl = ctrl.mech_control
1122        file_ctrl.add_file(big_image, filename='my_sample_scan.jpg')
1123        self.browser.getControl(
1124            name='upload_samplescanmanageupload').click()
1125        self.assertTrue(
1126            'Uploaded file is too big' in self.browser.contents)
1127        # We do not rely on filename extensions given by uploaders
1128        image = open(SAMPLE_IMAGE, 'rb')  # a jpg-file
1129        ctrl = self.browser.getControl(name='samplescanmanageupload')
1130        file_ctrl = ctrl.mech_control
1131        # Tell uploaded file is bmp
1132        file_ctrl.add_file(image, filename='my_sample_scan.bmp')
1133        self.browser.getControl(
1134            name='upload_samplescanmanageupload').click()
1135        self.assertTrue(
1136            # jpg file was recognized
1137            'File sample.jpg uploaded.' in self.browser.contents)
1138        # Delete file again
1139        self.browser.getControl(name='delete_samplescanmanageupload').click()
1140        self.assertTrue(
1141            'sample deleted' in self.browser.contents)
1142        # File names must meet several conditions
1143        bmp_image = open(SAMPLE_IMAGE_BMP, 'rb')
1144        ctrl = self.browser.getControl(name='samplescanmanageupload')
1145        file_ctrl = ctrl.mech_control
1146        file_ctrl.add_file(bmp_image, filename='my_sample_scan.bmp')
1147        self.browser.getControl(
1148            name='upload_samplescanmanageupload').click()
1149        self.assertTrue('Only the following extensions are allowed'
1150            in self.browser.contents)
1151
1152    def test_verify_document(self):
1153        IWorkflowState(self.customer).setState('approved')
1154        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1155        self.browser.open(self.customer_path + '/documents/DOC1/manage')
1156        image = open(SAMPLE_IMAGE, 'rb')
1157        ctrl = self.browser.getControl(name='samplescanmanageupload')
1158        file_ctrl = ctrl.mech_control
1159        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1160        self.browser.getControl(
1161            name='upload_samplescanmanageupload').click()
1162        IWorkflowState(self.document).setState(SUBMITTED)
1163        # Only after verifying the document, sample_md5 is set
1164        self.assertEqual(
1165            getattr(self.document, 'sample_md5', None), None)
1166        self.browser.open(self.documents_path + '/DOC1/trigtrans')
1167        self.browser.getControl(name="transition").value = ['verify']
1168        self.browser.getControl("Apply").click()
1169        self.assertEqual(
1170            getattr(self.document, 'sample_md5', None),
1171                    '1d1ab893e87c240afb2104d61ddfe180')
1172
1173    def test_manage_upload_pdf_file(self):
1174        # Managers can upload a file via the DocumentManageFormPage
1175        # The image is stored even if form has errors
1176        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1177        self.browser.open(self.customer_path + '/documents')
1178        self.browser.getControl("Add document").click()
1179        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
1180        self.browser.getControl(name="form.title").value = 'My PDF Document'
1181        self.browser.getControl("Add document").click()
1182        docid = [
1183            i for i in self.customer['documents'].keys() if len(i) > 10][0]
1184        self.browser.open(self.documents_path + '/%s/manage' % docid)
1185        # Create a pseudo image file and select it to be uploaded
1186        image = open(SAMPLE_IMAGE, 'rb')
1187        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1188        file_ctrl = ctrl.mech_control
1189        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1190        self.browser.getControl(
1191            name='upload_pdfscanmanageupload').click()
1192        self.assertTrue(
1193            'pdf file format expected' in self.browser.contents)
1194        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1195        file_ctrl = ctrl.mech_control
1196        file_ctrl.add_file(image, filename='my_sample_scan.pdf')
1197        self.browser.getControl(
1198            name='upload_pdfscanmanageupload').click()
1199        self.assertTrue(
1200            'Could not determine file type' in self.browser.contents)
1201        pdf = open(SAMPLE_PDF, 'rb')
1202        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1203        file_ctrl = ctrl.mech_control
1204        file_ctrl.add_file(pdf, filename='my_sample_scan.pdf')
1205        self.browser.getControl(
1206            name='upload_pdfscanmanageupload').click()
1207        self.assertTrue(
1208            'href="http://localhost/app/customers/K1000000/'
1209            'documents/%s/sample.pdf">%s.pdf</a>'
1210            % (docid, docid[:9]) in self.browser.contents)
1211        # Browsing the link shows a real pdf
1212        self.browser.open('sample.pdf')
1213        self.assertEqual(
1214            self.browser.headers['content-type'], 'application/pdf')
1215        # The name of the downloaded file will be different
1216        self.assertEqual(
1217            self.browser.headers['Content-Disposition'],
1218            'attachment; filename="%s.pdf' % docid[:9])
1219
1220    def test_view_slips(self):
1221        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1222        # Officers can open the document overview
1223        self.browser.open(self.customer_path + '/documents')
1224        self.browser.getLink("Download documents overview").click()
1225        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1226        self.assertEqual(
1227            self.browser.headers['Content-Type'], 'application/pdf')
1228        path = os.path.join(samples_dir(), 'documents_overview_slip.pdf')
1229        open(path, 'wb').write(self.browser.contents)
1230        print "Sample PDF overview_slip.pdf written to %s" % path
1231        # Officers can open document slips which shows a thumbnail of
1232        # the jpeg file attached.
1233        file_id = IFileStoreNameChooser(self.document).chooseName(
1234            attr='sample.jpg')
1235        fs = ExtFileStore(root=self.dc_root)
1236        jpegfile = open(SAMPLE_IMAGE, 'rb')
1237        fs.createFile(file_id, jpegfile)
1238        self.browser.open(self.customer_path + '/documents/DOC1')
1239        self.browser.getLink("Download document slip").click()
1240        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1241        self.assertEqual(
1242            self.browser.headers['Content-Type'], 'application/pdf')
1243        path = os.path.join(samples_dir(), 'document_slip.pdf')
1244        open(path, 'wb').write(self.browser.contents)
1245        print "Sample document_slip.pdf written to %s" % path
1246        # Officers can open merged pdf document slips
1247        pdfdocument = createObject('waeup.CustomerPDFDocument')
1248        pdfdocument.title = u'My first document'
1249        self.customer['documents'].addDocument(pdfdocument)
1250        # Add pdf file
1251        file_id = IFileStoreNameChooser(pdfdocument).chooseName(
1252            attr='sample.pdf')
1253        fs = ExtFileStore(root=self.dc_root)
1254        pdffile = open(SAMPLE_PDF, 'rb')
1255        fs.createFile(file_id, pdffile)
1256        docid = [i for i in self.customer['documents'].keys()
1257                 if len(i) > 10][0]
1258        self.browser.open(self.customer_path + '/documents/' + docid)
1259        self.browser.getLink("Download document slip").click()
1260        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1261        self.assertEqual(
1262            self.browser.headers['Content-Type'], 'application/pdf')
1263        path = os.path.join(samples_dir(), 'pdfdocument_slip.pdf')
1264        open(path, 'wb').write(self.browser.contents)
1265        print "Sample pdfdocument_slip.pdf written to %s" % path
1266
1267    def test_get_setmd5_file(self):
1268        # A proper file name chooser is registered for customer documents.
1269        # This is not a UI test. It's just a functional test.
1270        file_id = IFileStoreNameChooser(self.document).chooseName(
1271            attr='sample')
1272        fs = ExtFileStore(root=self.dc_root)
1273        fs.createFile(file_id, StringIO('my sample 1'))
1274        result = fs.getFileByContext(self.document, attr='sample')
1275        self.assertEqual(
1276            file_id, '__file-customerdocument__01000/'
1277            'K1000000/sample_DOC1_K1000000')
1278        self.assertEqual(result.read(), 'my sample 1')
1279        self.assertEqual(
1280            self.document.connected_files[0][1].read(), 'my sample 1')
1281        self.document.setMD5()
1282        self.assertEqual(
1283            self.document.sample_md5, 'a406995ee8eb6772bacf51aa4b0caa24')
1284        return
1285
1286
1287class ContractUITests(CustomersFullSetup):
1288    # Tests for contract related views and pages
1289
1290    never_ending_button_text = (
1291        'Select payment method (final submission)')
1292
1293    def add_product_option(self, contract):
1294        prodoption = ProductOption()
1295        prodoption.title = u'Any product option'
1296        prodoption.fee = Decimal('88.8')
1297        prodoption.currency = 'EUR'
1298        contract.product_options = [prodoption, ]
1299
1300    def test_multiple_currencies(self):
1301        prodoption1 = ProductOption()
1302        prodoption1.title = u'Any product option in Euros'
1303        prodoption1.fee = Decimal('88.8')
1304        prodoption1.currency = 'EUR'
1305        prodoption2 = ProductOption()
1306        prodoption2.title = u'Any product option in Dollars'
1307        prodoption2.fee = Decimal('99.9')
1308        prodoption2.currency = 'USD'
1309        self.assertRaises(CurrencyMismatch,
1310                          setattr, self.contract,
1311                          'product_options',
1312                          [prodoption1, prodoption2]
1313                          )
1314
1315    def prepare_payment_select(self):
1316        IWorkflowState(self.customer).setState('approved')
1317        IWorkflowState(self.document).setState('verified')
1318        self.contract.document_object = self.document
1319        self.add_product_option(self.contract)
1320        IWorkflowState(self.contract).setState('created')
1321        # login as customer
1322        self.browser.open(self.login_path)
1323        self.browser.getControl(name="form.login").value = self.customer_id
1324        self.browser.getControl(name="form.password").value = 'cpwd'
1325        self.browser.getControl("Login").click()
1326
1327    def test_manage_contract(self):
1328        # Managers can access the pages of customer contractsconter
1329        # and can perform actions
1330        IWorkflowState(self.customer).setState(APPROVED)
1331        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1332        self.browser.open(self.customer_path)
1333        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1334        self.assertEqual(self.browser.url, self.customer_path)
1335        self.browser.open(self.customer_path)
1336        self.browser.getLink("Contracts").click()
1337        self.browser.getControl("Add contract").click()
1338        self.browser.getControl(name="contype").value = ['SampleContract']
1339        self.browser.getControl("Add contract").click()
1340        self.assertTrue('Sample Contract added.' in self.browser.contents)
1341        conid = [i for i in self.customer['contracts'].keys()
1342                 if len(i) > 10][0]
1343        contract = self.customer['contracts'][conid]
1344        self.assertEqual(
1345            self.browser.url,
1346            self.contracts_path + '/%s/selectproduct' % conid)
1347        # SAM is in the correct contract_category
1348        self.assertTrue('<option value="SAM">' in self.browser.contents)
1349        # So far last_product_id is None.
1350        self.assertTrue(
1351            self.customer['contracts'][conid].last_product_id is None)
1352        self.browser.getControl(name="form.product_object").value = ['SAM']
1353        self.browser.getControl("Save and proceed").click()
1354        self.assertEqual(
1355            self.browser.url, self.contracts_path + '/%s/manage' % conid)
1356        self.browser.getLink("View").click()
1357        self.assertEqual(
1358            self.browser.url, self.contracts_path + '/%s/index' % conid)
1359        self.assertEqual(contract.tc_dict, {'en': u'Hello world'})
1360
1361        # Transitions can be performed
1362        self.browser.getLink("Transition").click()
1363        self.browser.getControl(name="transition").value = ['submit']
1364        self.browser.getControl("Apply").click()
1365        self.browser.getLink("Transition").click()
1366        self.browser.getControl(name="transition").value = ['approve']
1367        self.browser.getControl("Apply").click()
1368        self.assertEqual(contract.state, 'approved')
1369
1370        # Even in state approved the official use data can be edited
1371        self.browser.open(self.contracts_path + '/%s/index' % conid)
1372        self.browser.getLink("Manage official data").click()
1373        self.browser.getControl(name="form.comment").value = u'Nice place'
1374        self.browser.getControl("Save").click()
1375        self.assertEqual(contract.comment, 'Nice place')
1376        self.assertTrue('Form has been saved.' in self.browser.contents)
1377
1378        # Contracts can be removed
1379        self.browser.getLink("Contracts").click()
1380        ctrl = self.browser.getControl(name='val_id')
1381        ctrl.getControl(value=contract.contract_id).selected = True
1382        self.browser.getControl("Remove selected", index=0).click()
1383        self.assertTrue('Successfully removed' in self.browser.contents)
1384
1385        # All actions are being logged
1386        logfile = os.path.join(
1387            self.app['datacenter'].storage, 'logs', 'customers.log')
1388        logcontent = open(logfile).read()
1389        self.assertTrue(
1390            'INFO - zope.mgr - K1000000 - %s - Contract created' % conid
1391            in logcontent)
1392        self.assertTrue(
1393            'INFO - zope.mgr - customers.browser.ContractAddFormPage '
1394            '- K1000000 - added: Sample Contract %s'
1395            % contract.contract_id in logcontent)
1396        self.assertTrue(
1397            'INFO - zope.mgr - K1000000 - %s - Contract submitted' % conid
1398            in logcontent)
1399        self.assertTrue(
1400            'INFO - zope.mgr - K1000000 - %s - Contract approved' % conid
1401            in logcontent)
1402        self.assertTrue(
1403            'INFO - zope.mgr - customers.browser.ContractsFormPage '
1404            '- K1000000 - removed: %s' % conid
1405            in logcontent)
1406
1407    def test_edit_sample_contract(self):
1408        # We add a second product.
1409        product = createObject('waeup.Product')
1410        product.product_id = u'LIC'
1411        product.title = u'Our License Product'
1412        product.contract_category = u'license'
1413        product.valid_from = date(2014, 12, 4)
1414        self.app['products'].addProduct(product)
1415        # Customers can manage contracts under certain conditions
1416        self.browser.open(self.login_path)
1417        self.browser.getControl(name="form.login").value = self.customer_id
1418        self.browser.getControl(name="form.password").value = 'cpwd'
1419        self.browser.getControl("Login").click()
1420        self.assertMatches(
1421            '...You logged in...', self.browser.contents)
1422        self.browser.getLink("Contracts").click()
1423        # Customer is in wrong state
1424        self.assertFalse('Add contract' in self.browser.contents)
1425        self.browser.open(self.contracts_path + '/addcontract')
1426        self.assertTrue(
1427            'The requested form is locked' in self.browser.contents)
1428        IWorkflowState(self.customer).setState(APPROVED)
1429        self.browser.open(self.contracts_path)
1430        # Now customer can add a contract
1431        self.browser.getControl("Add contract").click()
1432        self.browser.getControl(name="contype").value = ['SampleContract']
1433        self.browser.getControl("Add contract").click()
1434        self.assertTrue('Sample Contract added.' in self.browser.contents)
1435        conid = [i for i in self.customer['contracts'].keys()
1436                 if len(i) > 10][0]
1437        contract = self.customer['contracts'][conid]
1438        self.assertEqual(
1439            self.browser.url,
1440            self.contracts_path + '/%s/selectproduct' % conid)
1441        # SAM is in the correct contract_category ...
1442        self.assertTrue('<option value="SAM">' in self.browser.contents)
1443        # ... but LIC not.
1444        self.assertFalse('<option value="LIC">' in self.browser.contents)
1445        # So far last_product_id is None.
1446        self.assertTrue(
1447            self.customer['contracts'][conid].last_product_id is None)
1448        self.browser.getControl(name="form.product_object").value = ['SAM']
1449        self.browser.getControl("Save and proceed").click()
1450        self.assertEqual(
1451            self.browser.url, self.contracts_path + '/%s/edit' % conid)
1452        # Document is a required field on edit form page.
1453        self.browser.getControl("Save").click()
1454        self.assertTrue(
1455            'Document: <span class="error">Required input is missing.</span>'
1456            in self.browser.contents)
1457        # But our document can't be selected because it's not submitted
1458        self.assertFalse('My first document' in self.browser.contents)
1459        IWorkflowState(self.document).setState(SUBMITTED)
1460        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1461        self.browser.getControl(name="form.document_object").value = ['DOC1']
1462        self.browser.getControl("Save").click()
1463        # After saving the form, last_product_id and other attributes are set
1464        self.assertTrue('Form has been saved.' in self.browser.contents)
1465        self.assertEqual(
1466            self.customer['contracts'][conid].last_product_id, 'SAM')
1467        self.assertEqual(contract.title, 'Our Sample Product')
1468        self.assertEqual(contract.product_object, self.product)
1469        self.assertEqual(contract.document_object, self.document)
1470        # Saving the form again does not unset last_product_id
1471        self.browser.getControl("Save").click()
1472        self.assertEqual(
1473            self.customer['contracts'][conid].last_product_id, 'SAM')
1474        self.assertTrue('Form has been saved.' in self.browser.contents)
1475        # So far we have not yet set product options.
1476        # Unfortunately, we can't set them in test browser
1477        prodoption = ProductOption()
1478        prodoption.title = u'Any product option'
1479        prodoption.fee = Decimal('88.8')
1480        prodoption.currency = 'EUR'
1481        contract.product_options = [prodoption, ]
1482        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1483        # We can see both the stored and the recent product options
1484        # from the chosen product.
1485        self.assertTrue(
1486            '<option selected="selected" value="Any product option">'
1487            'Any product option @ 88.8 Euro</option>'
1488            in self.browser.contents)
1489        self.assertTrue('<option value="First option">First option '
1490                        '@ 99.9 US Dollar</option>' in self.browser.contents)
1491        # In test browser we can at least replace the option
1492        self.browser.getControl(
1493            name="form.product_options.0.").value = ['First option']
1494        self.assertEqual(
1495            contract.product_options[0].title, 'Any product option')
1496        self.browser.getControl("Save").click()
1497        self.assertEqual(contract.product_options[0].title, 'First option')
1498        self.browser.getLink("View").click()
1499        self.assertTrue(
1500            '<span>First option @ 99.9 US Dollar</span>'
1501            in self.browser.contents)
1502        self.assertEqual(
1503            self.browser.url, self.contracts_path + '/%s/index' % conid)
1504        # An href attribute is referring to the document and product objects
1505        self.assertTrue('<a href="http://localhost/app/products/SAM">SAM -'
1506            in self.browser.contents)
1507        self.assertTrue(
1508            '<a href="http://localhost/app/customers/K1000000/'
1509            'documents/DOC1">DOC1 -'
1510            in self.browser.contents)
1511        # Customer can submit the form if confirmation box is ticket.
1512        # The form is also saved.
1513        self.browser.getLink("Edit").click()
1514        self.browser.getControl("Proceed to checkout").click()
1515        self.assertTrue(
1516            'confirm your acceptance of these by ticking'
1517            in self.browser.contents)
1518        self.assertEqual(contract.state, 'created')
1519        self.browser.getControl(name="confirm_tc").value = True
1520        self.browser.getControl("Proceed to checkout").click()
1521        self.assertEqual(contract.state, 'created')
1522        radio_ctrl = self.browser.getControl(name='gw')
1523        radio_ctrl.value = [radio_ctrl.options[0]]  # pick first payment opt
1524        self.browser.getControl("Select payment method").click()
1525        # Select demo payment
1526        self.browser.getControl(name="cc_number").value = '123456789012345'
1527        self.browser.getControl(name="csc").value = '1234'
1528        self.browser.getControl("Authorize Payment").click()
1529        self.assertTrue(
1530            'Your payment will now be verified'
1531            in self.browser.contents)
1532        self.assertEqual(contract.state, 'awaiting')
1533        # Customer can't edit the contract once it has been submitted
1534        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1535        self.assertTrue(
1536            'The requested form is locked' in self.browser.contents)
1537
1538    def test_view_slips(self):
1539        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1540        # Officers can open the contract overview
1541        self.browser.open(self.customer_path + '/contracts')
1542        self.browser.getLink("Download contracts overview").click()
1543        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1544        self.assertEqual(
1545            self.browser.headers['Content-Type'], 'application/pdf')
1546        path = os.path.join(samples_dir(), 'contracts_overview_slip.pdf')
1547        open(path, 'wb').write(self.browser.contents)
1548        print "Sample PDF overview_slip.pdf written to %s" % path
1549        # Officers can open contract slips.
1550        # First we add a submitted document and a product.
1551        IWorkflowState(self.document).setState(SUBMITTED)
1552        self.contract.document_object = self.document
1553        self.contract.product_object = self.product
1554        self.contract.tc_dict = {'en': u'<strong>Hello world</strong>'}
1555        self.contract.valid_from = date(2015, 12, 4)
1556        self.contract.valid_to = 'anything'
1557        self.contract.title = u'Contract Title'
1558        self.browser.open(self.customer_path + '/contracts/CON1')
1559        self.browser.getLink("Download contract slip").click()
1560        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1561        self.assertEqual(
1562            self.browser.headers['Content-Type'], 'application/pdf')
1563        path = os.path.join(samples_dir(), 'contract_slip.pdf')
1564        open(path, 'wb').write(self.browser.contents)
1565        print "Sample contract_slip.pdf written to %s" % path
1566
1567    def test_contract_approval(self):
1568        # This is not a UI test. It's just a functional test.
1569        self.assertRaises(ConstraintNotSatisfied,
1570            self.contract.document_object, self.document)
1571        # Document must be at least submitted
1572        IWorkflowState(self.document).setState('submitted')
1573        self.contract.document_object = self.document
1574        IWorkflowState(self.contract).setState('submitted')
1575        self.assertRaises(InvalidTransitionError,
1576            IWorkflowInfo(self.contract).fireTransition, 'approve')
1577        # Customer must be approved and
1578        # document must be verified for the approval of contracts
1579        IWorkflowState(self.document).setState('verified')
1580        IWorkflowState(self.customer).setState('approved')
1581        IWorkflowInfo(self.contract).fireTransition('approve')
1582        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
1583
1584    def test_contract_approval_in_UI(self):
1585        # Now let's see what the UI says when trying to approve a contract
1586        # with unverified documents.
1587        IWorkflowState(self.customer).setState('approved')
1588        IWorkflowState(self.document).setState('submitted')
1589        self.contract.document_object = self.document
1590        IWorkflowState(self.contract).setState('submitted')
1591        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1592        self.browser.open(self.contracts_path + '/CON1/trigtrans')
1593        self.browser.getControl(name="transition").value = ['approve']
1594        self.browser.getControl("Apply").click()
1595        # InvalidTransitionError is catched
1596        self.assertTrue(
1597            '<div class="alert alert-warning">Attached documents '
1598            'must be verified first.</div>'
1599            in self.browser.contents)
1600        self.browser.open(self.contracts_path + '/CON1/trigtrans')
1601        IWorkflowState(self.document).setState('verified')
1602        self.browser.getControl(name="transition").value = ['approve']
1603        self.browser.getControl("Apply").click()
1604        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
1605
1606    def test_select_payment(self):
1607        # select payment
1608        self.prepare_payment_select()
1609        self.browser.open('%s/CON1/edit' % self.contracts_path)
1610        self.browser.getControl("Proceed to checkout").click()
1611        self.assertTrue(
1612            "Select payment method" in self.browser.contents)
1613        self.assertTrue(
1614            'Credit Card (Demo Payments)' in self.browser.contents)
1615
1616    def test_select_payment_no_choice(self):
1617        # we get warned if no payment was selected
1618        self.prepare_payment_select()
1619        self.browser.open(
1620            '%s/CON1/select_payment_method' % self.contracts_path)
1621        self.browser.getControl(self.never_ending_button_text).click()
1622        self.assertTrue(
1623            'Please pick a payment method' in self.browser.contents)
1624
1625    def test_select_payment_demo_provider(self):
1626        # we can proceed with payments if we select a payment method
1627        self.prepare_payment_select()
1628        self.browser.open(
1629            '%s/CON1/select_payment_method' % self.contracts_path)
1630        radio_ctrl = self.browser.getControl(name='gw')
1631        radio_ctrl.displayValue = ['Credit Card (Demo Payments)']
1632        self.browser.getControl(self.never_ending_button_text).click()
Note: See TracBrowser for help on using the repository browser.