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

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

Adjust tests.

  • Property svn:keywords set to Id
File size: 68.1 KB
Line 
1## $Id: test_browser.py 12259 2014-12-18 15:47:12Z 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 pytz
24import base64
25from datetime import datetime, timedelta, date
26from StringIO import StringIO
27import os
28import grok
29from zc.async.testing import wait_for_result
30from zope.event import notify
31from zope.component import createObject, queryUtility, getUtility
32from zope.component.hooks import setSite, clearSite
33from zope.schema.interfaces import ConstraintNotSatisfied
34from zope.catalog.interfaces import ICatalog
35from zope.security.interfaces import Unauthorized
36from zope.securitypolicy.interfaces import IPrincipalRoleManager
37from zope.testbrowser.testing import Browser
38from hurry.workflow.interfaces import (
39    IWorkflowInfo, IWorkflowState, InvalidTransitionError)
40from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
41from waeup.ikoba.app import Company
42from waeup.ikoba.customers.interfaces import ICustomersUtils
43from waeup.ikoba.customers.customer import Customer
44from waeup.ikoba.interfaces import (
45    IUserAccount, IJobManager, APPROVED, SUBMITTED,
46    IFileStoreNameChooser, IExtFileStore, IFileStoreHandler)
47from waeup.ikoba.imagestorage import (
48    FileStoreNameChooser, ExtFileStore, DefaultFileStoreHandler,
49    DefaultStorage)
50from waeup.ikoba.authentication import LocalRoleSetEvent
51from waeup.ikoba.tests.test_async import FunctionalAsyncTestCase
52from waeup.ikoba.interfaces import VERIFIED
53from waeup.ikoba.browser.tests.test_pdf import samples_dir
54
55PH_LEN = 15911  # Length of placeholder file
56
57SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
58SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
59SAMPLE_PDF = os.path.join(os.path.dirname(__file__), 'test_pdf.pdf')
60
61def lookup_submit_value(name, value, browser):
62    """Find a button with a certain value."""
63    for num in range(0, 100):
64        try:
65            button = browser.getControl(name=name, index=num)
66            if button.value.endswith(value):
67                return button
68        except IndexError:
69            break
70    return None
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(self):
84        super(CustomersFullSetup, self).setUp()
85
86        # Setup a sample site for each test
87        app = Company()
88        self.dc_root = tempfile.mkdtemp()
89        app['datacenter'].setStoragePath(self.dc_root)
90
91        # Prepopulate the ZODB...
92        self.getRootFolder()['app'] = app
93        # we add the site immediately after creation to the
94        # ZODB. Catalogs and other local utilities are not setup
95        # before that step.
96        self.app = self.getRootFolder()['app']
97        # Set site here. Some of the following setup code might need
98        # to access grok.getSite() and should get our new app then
99        setSite(app)
100
101        # Add some products
102        self.product = createObject('waeup.Product')
103        self.product.product_id = u'SAM'
104        self.product.title = u'Our Samle Product'
105        self.product.contract_category = u'sample'
106        self.app['products'].addProduct(self.product)
107
108        # Add customer with subobjects
109        customer = createObject('waeup.Customer')
110        customer.firstname = u'Anna'
111        customer.lastname = u'Tester'
112        customer.reg_number = u'123'
113        customer.sex = u'm'
114        customer.email = 'aa@aa.ng'
115        customer.phone = u'1234'
116        customer.date_of_birth = date(1981, 2, 4)
117        self.app['customers'].addCustomer(customer)
118        self.customer_id = customer.customer_id
119        self.customer = self.app['customers'][self.customer_id]
120        self.document = createObject('waeup.CustomerSampleDocument')
121        self.document.title = u'My first document'
122        self.document.document_id = u'DOC1'
123        self.customer['documents'].addDocument(self.document)
124        self.contract = createObject('waeup.SampleContract')
125        self.contract.title = u'My first contract'
126        self.contract.contract_id = u'CON1'
127        self.customer['contracts'].addContract(self.contract)
128
129        # Set password
130        IUserAccount(
131            self.app['customers'][self.customer_id]).setPassword('cpwd')
132
133        self.login_path = 'http://localhost/app/login'
134        self.container_path = 'http://localhost/app/customers'
135        self.manage_container_path = self.container_path + '/@@manage'
136        self.add_customer_path = self.container_path + '/addcustomer'
137        self.customer_path = self.container_path + '/' + self.customer_id
138        self.manage_customer_path = self.customer_path + '/manage_base'
139        self.trigtrans_path = self.customer_path + '/trigtrans'
140        self.history_path = self.customer_path + '/history'
141        self.documents_path = self.customer_path + '/documents'
142        self.contracts_path = self.customer_path + '/contracts'
143
144        # Update the catalog
145        notify(grok.ObjectModifiedEvent(self.customer))
146
147        # Put the prepopulated site into test ZODB and prepare test
148        # browser
149        self.browser = Browser()
150        self.browser.handleErrors = False
151
152    def tearDown(self):
153        super(CustomersFullSetup, self).tearDown()
154        clearSite()
155        shutil.rmtree(self.dc_root)
156
157
158class CustomersContainerUITests(CustomersFullSetup):
159    # Tests for CustomersContainer class views and pages
160
161    layer = FunctionalLayer
162
163    def test_anonymous_access(self):
164        # Anonymous users can't access customers containers
165        self.assertRaises(
166            Unauthorized, self.browser.open, self.container_path)
167        self.assertRaises(
168            Unauthorized, self.browser.open, self.manage_container_path)
169        return
170
171    def test_manage_access(self):
172        # Managers can access the view page of customers
173        # containers and can perform actions
174        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
175        self.browser.open(self.container_path)
176        self.assertEqual(self.browser.headers['Status'], '200 Ok')
177        self.assertEqual(self.browser.url, self.container_path)
178        self.browser.getLink("Manage customer section").click()
179        self.assertEqual(self.browser.headers['Status'], '200 Ok')
180        self.assertEqual(self.browser.url, self.manage_container_path)
181        return
182
183    def test_add_search_delete_customers(self):
184        # Managers can add search and remove customers
185        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
186        self.browser.open(self.manage_container_path)
187        self.browser.getLink("Add customer").click()
188        self.assertEqual(self.browser.headers['Status'], '200 Ok')
189        self.assertEqual(self.browser.url, self.add_customer_path)
190        self.browser.getControl(name="form.firstname").value = 'Bob'
191        self.browser.getControl(name="form.lastname").value = 'Tester'
192        self.browser.getControl(name="form.reg_number").value = '123'
193        self.browser.getControl("Create customer record").click()
194        self.assertTrue('Registration number exists already'
195            in self.browser.contents)
196        self.browser.getControl(name="form.reg_number").value = '1234'
197        self.browser.getControl("Create customer").click()
198        self.assertTrue('Customer created' in self.browser.contents)
199
200        # Registration must be unique
201        self.browser.getLink("Manage").click()
202        self.browser.getControl(name="form.reg_number").value = '123'
203        self.browser.getControl("Save").click()
204        self.assertMatches('...Registration number exists...',
205                           self.browser.contents)
206
207        # We can find a customer with a certain customer_id
208        self.browser.open(self.container_path)
209        self.browser.getControl("Find customer(s)").click()
210        self.assertTrue('Empty search string' in self.browser.contents)
211        self.browser.getControl(name="searchtype").value = ['customer_id']
212        self.browser.getControl(name="searchterm").value = self.customer_id
213        self.browser.getControl("Find customer(s)").click()
214        self.assertTrue('Anna Tester' in self.browser.contents)
215
216        # We can find a customer by searching for all kind of name parts
217        self.browser.open(self.manage_container_path)
218        self.browser.getControl("Find customer(s)").click()
219        self.assertTrue('Empty search string' in self.browser.contents)
220        self.browser.getControl(name="searchtype").value = ['fullname']
221        self.browser.getControl(name="searchterm").value = 'Anna Tester'
222        self.browser.getControl("Find customer(s)").click()
223        self.assertTrue('Anna Tester' in self.browser.contents)
224        self.browser.open(self.manage_container_path)
225        self.browser.getControl(name="searchtype").value = ['fullname']
226        self.browser.getControl(name="searchterm").value = 'Anna'
227        self.browser.getControl("Find customer(s)").click()
228        self.assertTrue('Anna Tester' in self.browser.contents)
229        self.browser.open(self.manage_container_path)
230        self.browser.getControl(name="searchtype").value = ['fullname']
231        self.browser.getControl(name="searchterm").value = 'Tester'
232        self.browser.getControl("Find customer(s)").click()
233        self.assertTrue('Anna Tester' in self.browser.contents)
234        self.browser.open(self.manage_container_path)
235        self.browser.getControl(name="searchtype").value = ['fullname']
236        self.browser.getControl(name="searchterm").value = 'An'
237        self.browser.getControl("Find customer(s)").click()
238        self.assertFalse('Anna Tester' in self.browser.contents)
239        self.browser.open(self.manage_container_path)
240        self.browser.getControl(name="searchtype").value = ['fullname']
241        self.browser.getControl(name="searchterm").value = 'An*'
242        self.browser.getControl("Find customer(s)").click()
243        self.assertTrue('Anna Tester' in self.browser.contents)
244        self.browser.open(self.manage_container_path)
245        self.browser.getControl(name="searchtype").value = ['fullname']
246        self.browser.getControl(name="searchterm").value = 'tester'
247        self.browser.getControl("Find customer(s)").click()
248        self.assertTrue('Anna Tester' in self.browser.contents)
249        self.browser.open(self.manage_container_path)
250        self.browser.getControl(name="searchtype").value = ['fullname']
251        self.browser.getControl(name="searchterm").value = 'Tester Ana'
252        self.browser.getControl("Find customer(s)").click()
253        self.assertFalse('Anna Tester' in self.browser.contents)
254        self.browser.open(self.manage_container_path)
255        self.browser.getControl(name="searchtype").value = ['fullname']
256        self.browser.getControl(name="searchterm").value = 'Tester Anna'
257        self.browser.getControl("Find customer(s)").click()
258        self.assertTrue('Anna Tester' in self.browser.contents)
259        # The old searchterm will be used again
260        self.browser.getControl("Find customer(s)").click()
261        self.assertTrue('Anna Tester' in self.browser.contents)
262
263        # We can find suspended customers
264        self.customer.suspended = True
265        notify(grok.ObjectModifiedEvent(self.customer))
266        self.browser.open(self.manage_container_path)
267        self.browser.getControl(name="searchtype").value = ['suspended']
268        self.browser.getControl("Find customer(s)").click()
269        self.assertTrue('Anna Tester' in self.browser.contents)
270
271        # Removed customers won't be found
272        ctrl = self.browser.getControl(name='entries')
273        ctrl.getControl(value=self.customer_id).selected = True
274        self.browser.getControl("Remove selected", index=0).click()
275        self.assertTrue('Successfully removed' in self.browser.contents)
276        self.browser.getControl(name="searchtype").value = ['customer_id']
277        self.browser.getControl(name="searchterm").value = self.customer_id
278        self.browser.getControl("Find customer(s)").click()
279        self.assertTrue('No customer found' in self.browser.contents)
280        return
281
282class OfficerUITests(CustomersFullSetup):
283    # Tests for Customer class views and pages
284
285    def test_basic_auth(self):
286        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
287        self.browser.open('http://localhost/app')
288        self.browser.getLink("Logout").click()
289        self.assertTrue('You have been logged out' in self.browser.contents)
290        # But we are still logged in since we've used basic authentication here.
291        # Wikipedia says: Existing browsers retain authentication information
292        # until the tab or browser is closed or the user clears the history.
293        # HTTP does not provide a method for a server to direct clients to
294        # discard these cached credentials. This means that there is no
295        # effective way for a server to "log out" the user without closing
296        # the browser. This is a significant defect that requires browser
297        # manufacturers to support a "logout" user interface element ...
298        self.assertTrue('Manager' in self.browser.contents)
299
300    def test_basic_auth_base64(self):
301        auth_token = base64.b64encode('mgr:mgrpw')
302        self.browser.addHeader('Authorization', 'Basic %s' % auth_token)
303        self.browser.open(self.manage_container_path)
304        self.assertEqual(self.browser.headers['Status'], '200 Ok')
305
306    def test_manage_access(self):
307        # Managers can access the pages of customers
308        # and can perform actions
309        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
310        self.browser.open(self.customer_path)
311        self.assertEqual(self.browser.headers['Status'], '200 Ok')
312        self.assertEqual(self.browser.url, self.customer_path)
313        self.browser.getLink("Transition").click()
314        self.assertEqual(self.browser.headers['Status'], '200 Ok')
315        # Managers can trigger transitions
316        self.browser.getControl(name="transition").value = ['start']
317        self.browser.getControl("Apply now").click()
318        # Managers can edit base
319        self.browser.open(self.customer_path)
320        self.browser.getLink("Manage").click()
321        self.assertEqual(self.browser.url, self.manage_customer_path)
322        self.assertEqual(self.browser.headers['Status'], '200 Ok')
323        self.browser.getControl(name="form.firstname").value = 'John'
324        self.browser.getControl(name="form.lastname").value = 'Tester'
325        self.browser.getControl(name="form.reg_number").value = '345'
326        self.browser.getControl(name="password").value = 'secret'
327        self.browser.getControl(name="control_password").value = 'secret'
328        self.browser.getControl("Save").click()
329        self.assertMatches('...Form has been saved...',
330                           self.browser.contents)
331
332    def test_manage_contact_customer(self):
333        # Managers can contact customer
334        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
335        self.customer.email = None
336        self.browser.open(self.customer_path)
337        self.browser.getLink("Send email").click()
338        self.browser.getControl(name="form.subject").value = 'Important subject'
339        self.browser.getControl(name="form.body").value = 'Hello!'
340        self.browser.getControl("Send message now").click()
341        self.assertTrue('An smtp server error occurred' in self.browser.contents)
342        self.customer.email = 'xx@yy.zz'
343        self.browser.getControl("Send message now").click()
344        self.assertTrue('Your message has been sent' in self.browser.contents)
345        return
346
347    def test_manage_upload_passport(self):
348        # Managers can upload a file via the CustomerBaseManageFormPage
349        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
350        self.browser.open(self.manage_customer_path)
351        image = open(SAMPLE_IMAGE_BMP, 'rb')
352        ctrl = self.browser.getControl(name='passportmanageupload')
353        file_ctrl = ctrl.mech_control
354        file_ctrl.add_file(image, filename='my_photo.bmp')
355        self.browser.getControl(
356            name='upload_passportmanageupload').click()
357        self.assertTrue('jpg file extension expected'
358            in self.browser.contents)
359        ctrl = self.browser.getControl(name='passportmanageupload')
360        file_ctrl = ctrl.mech_control
361        image = open(SAMPLE_IMAGE, 'rb')
362        file_ctrl.add_file(image, filename='my_photo.jpg')
363        self.browser.getControl(
364            name='upload_passportmanageupload').click()
365        self.assertTrue(
366            'src="http://localhost/app/customers/K1000000/passport.jpg"'
367            in self.browser.contents)
368        # We remove the passport file again
369        self.browser.open(self.manage_customer_path)
370        self.browser.getControl('Delete').click()
371        self.assertTrue('passport.jpg deleted' in self.browser.contents)
372
373
374    def test_manage_workflow(self):
375        # Managers can pass through the whole workflow
376        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
377        customer = self.app['customers'][self.customer_id]
378        self.browser.open(self.trigtrans_path)
379        self.browser.getControl(name="transition").value = ['start']
380        self.browser.getControl("Apply now").click()
381        self.browser.open(self.trigtrans_path)
382        self.browser.getControl(name="transition").value = ['request']
383        self.browser.getControl("Apply now").click()
384        self.browser.open(self.trigtrans_path)
385        self.browser.getControl(name="transition").value = ['reject']
386        self.browser.getControl("Apply now").click()
387        self.browser.open(self.trigtrans_path)
388        self.browser.getControl(name="transition").value = ['request']
389        self.browser.getControl("Apply now").click()
390        self.browser.open(self.trigtrans_path)
391        self.browser.getControl(name="transition").value = ['approve']
392        self.browser.getControl("Apply now").click()
393        self.browser.open(self.trigtrans_path)
394        self.browser.getControl(name="transition").value = ['reset1']
395        self.browser.getControl("Apply now").click()
396        return
397
398    def test_manage_import(self):
399        # Managers can import customer data files
400        datacenter_path = 'http://localhost/app/datacenter'
401        # Prepare a csv file for customers
402        open('customers.csv', 'wb').write(
403"""firstname,lastname,reg_number,date_of_birth,email,phone,sex,password
404Aaren,Pieri,1,1990-01-02,aa@aa.ng,1234,m,mypwd1
405Claus,Finau,2,1990-01-03,aa@aa.ng,1234,m,mypwd1
406Brit,Berson,2,1990-01-04,aa@aa.ng,1234,m,mypwd1
407""")
408        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
409        self.browser.open(datacenter_path)
410        self.browser.getLink('Upload data').click()
411        filecontents = StringIO(open('customers.csv', 'rb').read())
412        filewidget = self.browser.getControl(name='uploadfile:file')
413        filewidget.add_file(filecontents, 'text/plain', 'customers.csv')
414        self.browser.getControl(name='SUBMIT').click()
415        self.browser.getLink('Process data').click()
416        button = lookup_submit_value(
417            'select', 'customers_zope.mgr.csv', self.browser)
418        button.click()
419        importerselect = self.browser.getControl(name='importer')
420        modeselect = self.browser.getControl(name='mode')
421        importerselect.getControl('Customer Processor').selected = True
422        modeselect.getControl(value='create').selected = True
423        self.browser.getControl('Proceed to step 3').click()
424        self.assertTrue('Header fields OK' in self.browser.contents)
425        self.browser.getControl('Perform import').click()
426        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
427        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
428        self.assertTrue('Batch processing finished' in self.browser.contents)
429
430        # The customers are properly indexed and we can
431        # thus find a customer in  the department
432        self.browser.open(self.manage_container_path)
433        # We can search for a new customer by name ...
434        self.browser.getControl(name="searchtype").value = ['fullname']
435        self.browser.getControl(name="searchterm").value = 'Claus'
436        self.browser.getControl("Find customer(s)").click()
437        self.assertTrue('Claus Finau' in self.browser.contents)
438        # ... and check if the imported password has been properly set
439        ctrl = self.browser.getControl(name='entries')
440        value = ctrl.options[0]
441        claus = self.app['customers'][value]
442        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
443        return
444
445    def test_activate_deactivate_buttons(self):
446        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
447        self.browser.open(self.customer_path)
448        self.browser.getLink("Deactivate").click()
449        self.assertTrue(
450            'Customer account has been deactivated.' in self.browser.contents)
451        self.assertTrue(
452            'Base Data (account deactivated)' in self.browser.contents)
453        self.assertTrue(self.customer.suspended)
454        self.browser.getLink("Activate").click()
455        self.assertTrue(
456            'Customer account has been activated.' in self.browser.contents)
457        self.assertFalse(
458            'Base Data (account deactivated)' in self.browser.contents)
459        self.assertFalse(self.customer.suspended)
460        # History messages have been added ...
461        self.browser.getLink("History").click()
462        self.assertTrue(
463            'Customer account deactivated by Manager<br />' in self.browser.contents)
464        self.assertTrue(
465            'Customer account activated by Manager<br />' in self.browser.contents)
466        # ... and actions have been logged.
467        logfile = os.path.join(
468            self.app['datacenter'].storage, 'logs', 'customers.log')
469        logcontent = open(logfile).read()
470        self.assertTrue('zope.mgr - customers.browser.CustomerDeactivatePage - '
471                        'K1000000 - account deactivated' in logcontent)
472        self.assertTrue('zope.mgr - customers.browser.CustomerActivatePage - '
473                        'K1000000 - account activated' in logcontent)
474
475
476    def test_login_as_customer(self):
477        # CustomerImpersonators can login as customer
478        self.app['users'].addUser('mrofficer', 'mrofficersecret')
479        self.app['users']['mrofficer'].email = 'mrofficer@foo.ng'
480        self.app['users']['mrofficer'].title = 'Harry Actor'
481        prmglobal = IPrincipalRoleManager(self.app)
482        prmglobal.assignRoleToPrincipal('waeup.CustomerImpersonator', 'mrofficer')
483        prmglobal.assignRoleToPrincipal('waeup.CustomersManager', 'mrofficer')
484        # Login as customer impersonator
485        self.browser.open(self.login_path)
486        self.browser.getControl(name="form.login").value = 'mrofficer'
487        self.browser.getControl(name="form.password").value = 'mrofficersecret'
488        self.browser.getControl("Login").click()
489        self.assertMatches('...You logged in...', self.browser.contents)
490        self.browser.open(self.customer_path)
491        self.browser.getLink("Login as").click()
492        self.browser.getControl("Set password now").click()
493        temp_password = self.browser.getControl(name='form.password').value
494        self.browser.getControl("Login now").click()
495        self.assertMatches(
496            '...You successfully logged in as...', self.browser.contents)
497        # We are logged in as customer and can see the 'My Data' tab
498        self.assertMatches(
499            '...<a href="#" class="dropdown-toggle" data-toggle="dropdown">...',
500            self.browser.contents)
501        self.assertMatches(
502            '...My Data...',
503            self.browser.contents)
504        self.browser.getLink("Logout").click()
505        # The customer can't login with the original password ...
506        self.browser.open(self.login_path)
507        self.browser.getControl(name="form.login").value = self.customer_id
508        self.browser.getControl(name="form.password").value = 'cpwd'
509        self.browser.getControl("Login").click()
510        self.assertMatches(
511            '...Your account has been temporarily deactivated...',
512            self.browser.contents)
513        # ... but with the temporary password
514        self.browser.open(self.login_path)
515        self.browser.getControl(name="form.login").value = self.customer_id
516        self.browser.getControl(name="form.password").value = temp_password
517        self.browser.getControl("Login").click()
518        self.assertMatches('...You logged in...', self.browser.contents)
519        # Creation of temp_password is properly logged
520        logfile = os.path.join(
521            self.app['datacenter'].storage, 'logs', 'customers.log')
522        logcontent = open(logfile).read()
523        self.assertTrue(
524            'mrofficer - customers.browser.LoginAsCustomerStep1 - K1000000 - '
525            'temp_password generated: %s' % temp_password in logcontent)
526
527
528class CustomerUITests(CustomersFullSetup):
529    # Tests for Customer class views and pages
530
531    def test_customer_change_password(self):
532        # Customers can change the password
533        self.customer.personal_updated = datetime.utcnow()
534        self.browser.open(self.login_path)
535        self.browser.getControl(name="form.login").value = self.customer_id
536        self.browser.getControl(name="form.password").value = 'cpwd'
537        self.browser.getControl("Login").click()
538        self.assertEqual(self.browser.url, self.customer_path)
539        self.assertTrue('You logged in' in self.browser.contents)
540        # Change password
541        self.browser.getLink("Change password").click()
542        self.browser.getControl(name="change_password").value = 'pw'
543        self.browser.getControl(
544            name="change_password_repeat").value = 'pw'
545        self.browser.getControl("Save").click()
546        self.assertTrue('Password must have at least' in self.browser.contents)
547        self.browser.getControl(name="change_password").value = 'new_password'
548        self.browser.getControl(
549            name="change_password_repeat").value = 'new_passssword'
550        self.browser.getControl("Save").click()
551        self.assertTrue('Passwords do not match' in self.browser.contents)
552        self.browser.getControl(name="change_password").value = 'new_password'
553        self.browser.getControl(
554            name="change_password_repeat").value = 'new_password'
555        self.browser.getControl("Save").click()
556        self.assertTrue('Password changed' in self.browser.contents)
557        # We are still logged in. Changing the password hasn't thrown us out.
558        self.browser.getLink("Base Data").click()
559        self.assertEqual(self.browser.url, self.customer_path)
560        # We can logout
561        self.browser.getLink("Logout").click()
562        self.assertTrue('You have been logged out' in self.browser.contents)
563        self.assertEqual(self.browser.url, 'http://localhost/app/index')
564        # We can login again with the new password
565        self.browser.getLink("Login").click()
566        self.browser.open(self.login_path)
567        self.browser.getControl(name="form.login").value = self.customer_id
568        self.browser.getControl(name="form.password").value = 'new_password'
569        self.browser.getControl("Login").click()
570        self.assertEqual(self.browser.url, self.customer_path)
571        self.assertTrue('You logged in' in self.browser.contents)
572        return
573
574    def test_customer_upload_passport(self):
575        # Customer cant login if their password is not set
576        IWorkflowInfo(self.customer).fireTransition('start')
577        self.browser.open(self.login_path)
578        self.browser.getControl(name="form.login").value = self.customer_id
579        self.browser.getControl(name="form.password").value = 'cpwd'
580        self.browser.getControl("Login").click()
581        self.assertMatches(
582            '...You logged in...', self.browser.contents)
583        # Admitted customer can upload a passport picture
584        self.browser.getLink("Change portrait").click()
585        ctrl = self.browser.getControl(name='passporteditupload')
586        file_obj = open(SAMPLE_IMAGE, 'rb')
587        file_ctrl = ctrl.mech_control
588        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
589        self.browser.getControl(
590            name='upload_passporteditupload').click()
591        self.assertTrue(
592            'src="http://localhost/app/customers/K1000000/passport.jpg"'
593            in self.browser.contents)
594
595    def test_customer_baseedit(self):
596        # Customers can change the password
597        self.customer.personal_updated = datetime.utcnow()
598        self.browser.open(self.login_path)
599        self.browser.getControl(name="form.login").value = self.customer_id
600        self.browser.getControl(name="form.password").value = 'cpwd'
601        self.browser.getControl("Login").click()
602        self.assertEqual(self.browser.url, self.customer_path)
603        self.assertTrue('You logged in' in self.browser.contents)
604        self.browser.getLink("Edit").click()
605        self.browser.getControl(name="form.email").value = 'new_email@aa.ng'
606        self.browser.getControl("Save").click()
607        self.assertMatches('...Form has been saved...',
608                           self.browser.contents)
609        # Customer can view history
610        self.browser.getLink("History").click()
611        self.assertMatches('...Customer created by system...',
612            self.browser.contents)
613
614    def test_customer_login(self):
615        # Customer cant login if their password is not set
616        self.customer.password = None
617        self.browser.open(self.login_path)
618        self.browser.getControl(name="form.login").value = self.customer_id
619        self.browser.getControl(name="form.password").value = 'cpwd'
620        self.browser.getControl("Login").click()
621        self.assertTrue(
622            'You entered invalid credentials.' in self.browser.contents)
623        # We set the password again
624        IUserAccount(
625            self.app['customers'][self.customer_id]).setPassword('cpwd')
626        # Customers can't login if their account is suspended/deactivated
627        self.customer.suspended = True
628        self.browser.open(self.login_path)
629        self.browser.getControl(name="form.login").value = self.customer_id
630        self.browser.getControl(name="form.password").value = 'cpwd'
631        self.browser.getControl("Login").click()
632        self.assertMatches(
633            '...<div class="alert alert-warning">'
634            'Your account has been deactivated.</div>...', self.browser.contents)
635        # If suspended_comment is set this message will be flashed instead
636        self.customer.suspended_comment = u'Aetsch baetsch!'
637        self.browser.getControl(name="form.login").value = self.customer_id
638        self.browser.getControl(name="form.password").value = 'cpwd'
639        self.browser.getControl("Login").click()
640        self.assertMatches(
641            '...<div class="alert alert-warning">Aetsch baetsch!</div>...',
642            self.browser.contents)
643        self.customer.suspended = False
644        # Customers can't login if a temporary password has been set and
645        # is not expired
646        self.app['customers'][self.customer_id].setTempPassword(
647            'anybody', 'temp_cpwd')
648        self.browser.open(self.login_path)
649        self.browser.getControl(name="form.login").value = self.customer_id
650        self.browser.getControl(name="form.password").value = 'cpwd'
651        self.browser.getControl("Login").click()
652        self.assertMatches(
653            '...Your account has been temporarily deactivated...',
654            self.browser.contents)
655        # The customer can login with the temporary password
656        self.browser.open(self.login_path)
657        self.browser.getControl(name="form.login").value = self.customer_id
658        self.browser.getControl(name="form.password").value = 'temp_cpwd'
659        self.browser.getControl("Login").click()
660        self.assertMatches(
661            '...You logged in...', self.browser.contents)
662        # Customer can view the base data
663        self.browser.open(self.customer_path)
664        self.assertEqual(self.browser.headers['Status'], '200 Ok')
665        self.assertEqual(self.browser.url, self.customer_path)
666        # When the password expires ...
667        delta = timedelta(minutes=11)
668        self.app['customers'][self.customer_id].temp_password[
669            'timestamp'] = datetime.utcnow() - delta
670        self.app['customers'][self.customer_id]._p_changed = True
671        # ... the customer will be automatically logged out
672        self.assertRaises(
673            Unauthorized, self.browser.open, self.customer_path)
674        # Then the customer can login with the original password
675        self.browser.open(self.login_path)
676        self.browser.getControl(name="form.login").value = self.customer_id
677        self.browser.getControl(name="form.password").value = 'cpwd'
678        self.browser.getControl("Login").click()
679        self.assertMatches(
680            '...You logged in...', self.browser.contents)
681
682    def test_change_password_request(self):
683        self.browser.open('http://localhost/app/changepw')
684        self.browser.getControl(name="form.identifier").value = '123'
685        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
686        self.browser.getControl("Send login credentials").click()
687        self.assertTrue('An email with' in self.browser.contents)
688
689class CustomerRegistrationTests(CustomersFullSetup):
690    # Tests for customer registration
691
692    layer = FunctionalLayer
693
694    def test_request_pw(self):
695        # Customer with wrong number can't be found.
696        self.browser.open('http://localhost/app/requestpw')
697        self.browser.getControl(name="form.firstname").value = 'Anna'
698        self.browser.getControl(name="form.number").value = 'anynumber'
699        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
700        self.browser.getControl("Send login credentials").click()
701        self.assertTrue('No customer found.'
702            in self.browser.contents)
703        # Anonymous is not informed that firstname verification failed.
704        # It seems that the record doesn't exist.
705        self.browser.open('http://localhost/app/requestpw')
706        self.browser.getControl(name="form.firstname").value = 'Johnny'
707        self.browser.getControl(name="form.number").value = '123'
708        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
709        self.browser.getControl("Send login credentials").click()
710        self.assertTrue('No customer found.'
711            in self.browser.contents)
712        # Even with the correct firstname we can't register if a
713        # password has been set and used.
714        self.browser.getControl(name="form.firstname").value = 'Anna'
715        self.browser.getControl(name="form.number").value = '123'
716        self.browser.getControl("Send login credentials").click()
717        self.assertTrue('Your password has already been set and used.'
718            in self.browser.contents)
719        self.browser.open('http://localhost/app/requestpw')
720        self.app['customers'][self.customer_id].password = None
721        # The firstname field, used for verification, is not case-sensitive.
722        self.browser.getControl(name="form.firstname").value = 'aNNa'
723        self.browser.getControl(name="form.number").value = '123'
724        self.browser.getControl(name="form.email").value = 'new@yy.zz'
725        self.browser.getControl("Send login credentials").click()
726        # Yeah, we succeded ...
727        self.assertTrue('Your request was successful.'
728            in self.browser.contents)
729        # ... and  customer can be found in the catalog via the email address
730        cat = queryUtility(ICatalog, name='customers_catalog')
731        results = list(
732            cat.searchResults(
733            email=('new@yy.zz', 'new@yy.zz')))
734        self.assertEqual(self.customer,results[0])
735        logfile = os.path.join(
736            self.app['datacenter'].storage, 'logs', 'main.log')
737        logcontent = open(logfile).read()
738        self.assertTrue('zope.anybody - customers.browser.CustomerRequestPasswordPage - '
739                        '123 (K1000000) - new@yy.zz' in logcontent)
740        return
741
742    def test_create_account(self):
743        # Customer with wrong number can't be found.
744        self.browser.open('http://localhost/app/createaccount')
745        self.browser.getControl(name="form.firstname").value = 'Ruben'
746        self.browser.getControl(name="form.lastname").value = 'Gonzales'
747        self.browser.getControl(name="form.email").value = 'newcustomer@xx.zz'
748        self.browser.getControl("Send login credentials").click()
749        self.assertTrue('Your request was successful.'
750            in self.browser.contents)
751        # ... and  customer can be found in the catalog via the email address
752        cat = queryUtility(ICatalog, name='customers_catalog')
753        results = list(
754            cat.searchResults(
755            email=('newcustomer@xx.zz', 'newcustomer@xx.zz')))
756        self.assertEqual(self.app['customers']['K1000001'], results[0])
757        self.assertEqual(self.app['customers']['K1000001'].firstname, 'Ruben')
758        self.assertEqual(self.app['customers']['K1000001'].lastname, 'Gonzales')
759        logfile = os.path.join(
760            self.app['datacenter'].storage, 'logs', 'main.log')
761        logcontent = open(logfile).read()
762        self.assertTrue('zope.anybody - customers.browser.CustomerCreateAccountPage - '
763                        'K1000001 - newcustomer@xx.zz' in logcontent)
764        return
765
766class CustomerDataExportTests(CustomersFullSetup, FunctionalAsyncTestCase):
767    # Tests for CustomersContainer class views and pages
768
769    layer = FunctionalLayer
770
771    def wait_for_export_job_completed(self):
772        # helper function waiting until the current export job is completed
773        manager = getUtility(IJobManager)
774        job_id = self.app['datacenter'].running_exports[0][0]
775        job = manager.get(job_id)
776        wait_for_result(job)
777        return job_id
778
779    def test_datacenter_export(self):
780        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
781        self.browser.open('http://localhost/app/datacenter/@@export')
782        self.browser.getControl(name="exporter").value = ['customers']
783        self.browser.getControl("Create CSV file").click()
784
785        # When the job is finished and we reload the page...
786        job_id = self.wait_for_export_job_completed()
787        # ... the csv file can be downloaded ...
788        self.browser.open('http://localhost/app/datacenter/@@export')
789        self.browser.getLink("Download").click()
790        self.assertEqual(self.browser.headers['content-type'],
791            'text/csv; charset=UTF-8')
792        self.assertTrue(
793            'filename="WAeUP.Ikoba_customers_%s.csv' % job_id in
794            self.browser.headers['content-disposition'])
795        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
796        job_id = self.app['datacenter'].running_exports[0][0]
797        # ... and discarded
798        self.browser.open('http://localhost/app/datacenter/@@export')
799        self.browser.getControl("Discard").click()
800        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
801        # Creation, downloading and discarding is logged
802        logfile = os.path.join(
803            self.app['datacenter'].storage, 'logs', 'datacenter.log')
804        logcontent = open(logfile).read()
805        self.assertTrue(
806            'zope.mgr - browser.pages.ExportCSVPage - exported: '
807            'customers, job_id=%s'
808            % job_id in logcontent
809            )
810        self.assertTrue(
811            'zope.mgr - browser.pages.ExportCSVView - downloaded: '
812            'WAeUP.Ikoba_customers_%s.csv, job_id=%s'
813            % (job_id, job_id) in logcontent
814            )
815        self.assertTrue(
816            'zope.mgr - browser.pages.ExportCSVPage - discarded: '
817            'job_id=%s' % job_id in logcontent
818            )
819
820
821class DocumentUITests(CustomersFullSetup):
822    # Tests for customer document related views and pages
823
824    def test_manage_document(self):
825        # Managers can access the pages of customer documentsconter
826        # and can perform actions
827        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
828        self.browser.open(self.customer_path)
829        self.assertEqual(self.browser.headers['Status'], '200 Ok')
830        self.assertEqual(self.browser.url, self.customer_path)
831        self.browser.open(self.customer_path)
832        self.browser.getLink("Documents", index=1).click()
833        self.browser.getControl("Add document").click()
834        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
835        self.browser.getControl(name="form.title").value = 'My PDF Document'
836        self.browser.getControl("Add document").click()
837        self.assertTrue('PDF Document added.' in self.browser.contents)
838        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
839        document = self.customer['documents'][docid]
840
841        # Document can be edited
842        self.browser.getLink(docid).click()
843        self.browser.getLink("Manage").click()
844        self.browser.getControl(name="form.title").value = 'My second doc'
845        self.browser.getControl("Save").click()
846        self.assertTrue('Form has been saved.' in self.browser.contents)
847        self.browser.getLink("View").click()
848        self.assertEqual(self.browser.url,
849            self.documents_path + '/' + docid + '/index')
850
851        # Transitions can be performed
852        self.browser.getLink("Transition").click()
853        self.browser.getControl(name="transition").value = ['submit']
854        self.browser.getControl("Apply now").click()
855        self.browser.getLink("Transition").click()
856        # Document can only be verified if files have been uploaded before
857        self.browser.getControl(name="transition").value = ['verify']
858        self.browser.getControl("Apply now").click()
859        self.assertTrue('No file uploaded' in self.browser.contents)
860        self.assertEqual(document.state, 'submitted')
861        # We set state here manually (verification is tested in test_verify_document)
862        IWorkflowState(document).setState(VERIFIED)
863
864        # Manage button and form is no longer available
865        self.browser.open(self.documents_path + '/' + docid + '/index')
866        self.assertFalse(
867            'href="http://localhost/app/customers/K1000000/documents/%s/manage"'
868            % docid in self.browser.contents)
869        self.browser.open(self.documents_path + '/' + docid + '/manage')
870        self.assertTrue(
871            'The requested form is locked (read-only)'
872            in self.browser.contents)
873
874        # Documents can be removed
875        self.browser.getLink("Documents", index=1).click()
876        ctrl = self.browser.getControl(name='val_id')
877        ctrl.getControl(value=document.document_id).selected = True
878        self.browser.getControl("Remove selected", index=0).click()
879        self.assertTrue('Successfully removed' in self.browser.contents)
880
881        # All actions are being logged
882        logfile = os.path.join(
883            self.app['datacenter'].storage, 'logs', 'customers.log')
884        logcontent = open(logfile).read()
885
886        self.assertTrue(
887            'INFO - system - K1000000 - DOC1 - Document created'
888            in logcontent)
889        self.assertTrue(
890            'INFO - zope.mgr - customers.browser.DocumentAddFormPage '
891            '- K1000000 - added: PDF Document %s'
892            % document.document_id in logcontent)
893        self.assertTrue(
894            'INFO - zope.mgr - customers.browser.DocumentManageFormPage '
895            '- K1000000 - %s - saved: title' % docid
896            in logcontent)
897        self.assertTrue(
898            'INFO - zope.mgr - K1000000 - %s - Submitted for verification'
899            % docid in logcontent)
900        self.assertTrue(
901            'INFO - zope.mgr - customers.browser.DocumentsManageFormPage '
902            '- K1000000 - removed: %s' % docid
903            in logcontent)
904
905    def test_edit_sample_document(self):
906        # Customers can manage documents under certain conditions
907        self.browser.open(self.login_path)
908        self.browser.getControl(name="form.login").value = self.customer_id
909        self.browser.getControl(name="form.password").value = 'cpwd'
910        self.browser.getControl("Login").click()
911        self.assertMatches(
912            '...You logged in...', self.browser.contents)
913        self.browser.getLink("Documents").click()
914        self.browser.getControl("Add document").click()
915        self.browser.getControl(name="doctype").value = ['CustomerSampleDocument']
916        self.browser.getControl(name="form.title").value = 'My Sample Document'
917        self.browser.getControl("Add document").click()
918        self.assertTrue('Sample Document added.' in self.browser.contents)
919        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
920        document = self.customer['documents'][docid]
921
922        # Document can be edited ...
923        self.browser.getLink(docid).click()
924        self.browser.open(self.documents_path + '/' + docid + '/edit')
925        #self.browser.getLink("Edit").click()
926        self.assertTrue('The requested form is locked' in self.browser.contents)
927        # Customer is in wrong state
928        IWorkflowState(self.customer).setState(APPROVED)
929        self.browser.open(self.documents_path + '/' + docid + '/edit')
930        self.browser.getControl(name="form.title").value = 'My second doc'
931        self.browser.getControl("Save").click()
932        self.assertEqual(document.title, 'My second doc')
933        self.assertTrue('Form has been saved.' in self.browser.contents)
934        self.browser.getLink("View").click()
935        self.assertEqual(
936            self.browser.url, self.documents_path + '/%s/index' % docid)
937        # Costumer can upload a document.
938        self.browser.getLink("Edit").click()
939        ctrl = self.browser.getControl(name='samplescaneditupload')
940        file_obj = open(SAMPLE_IMAGE, 'rb')
941        file_ctrl = ctrl.mech_control
942        file_ctrl.add_file(file_obj, filename='my_document.jpg')
943        self.browser.getControl(
944            name='upload_samplescaneditupload').click()
945        self.assertTrue(
946            'href="http://localhost/app/customers/K1000000/documents/%s/sample"'
947            % docid in self.browser.contents)
948        # Costumer can submit the form. The form is also saved.
949        self.browser.getControl(name="form.title").value = 'My third doc'
950        self.browser.getControl("Final Submit").click()
951        self.assertEqual(document.title, 'My third doc')
952        self.assertEqual(document.state, 'submitted')
953        self.assertTrue('Document State: submitted for verification' in self.browser.contents)
954        # Customer can't edit the document once it has been submitted
955        self.browser.open(self.documents_path + '/%s/edit' % docid)
956        self.assertTrue('The requested form is locked' in self.browser.contents)
957
958    def test_manage_upload_sample_file(self):
959        # Managers can upload a file via the DocumentManageFormPage
960        # The image is stored even if form has errors
961        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
962        self.browser.open(self.customer_path + '/documents/DOC1/manage')
963        # Create a pseudo image file and select it to be uploaded
964        image = open(SAMPLE_IMAGE, 'rb')
965        ctrl = self.browser.getControl(name='samplescanmanageupload')
966        file_ctrl = ctrl.mech_control
967        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
968        # The Save action does not upload files
969        self.browser.getControl("Save").click() # submit form
970        self.assertFalse(
971            'href="http://localhost/app/customers/K1000000/documents/DOC1/sample"'
972            in self.browser.contents)
973        # ... but the correct upload submit button does
974        image = open(SAMPLE_IMAGE)
975        ctrl = self.browser.getControl(name='samplescanmanageupload')
976        file_ctrl = ctrl.mech_control
977        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
978        self.browser.getControl(
979            name='upload_samplescanmanageupload').click()
980        self.assertTrue(
981            'href="http://localhost/app/customers/K1000000/documents/DOC1/sample"'
982            in self.browser.contents)
983        # Browsing the link shows a real image
984        self.browser.open('sample')
985        self.assertEqual(
986            self.browser.headers['content-type'], 'image/jpeg')
987        self.assertEqual(len(self.browser.contents), 2787)
988        # We can't reupload a file. The existing file must be deleted first.
989        self.browser.open(self.customer_path + '/documents/DOC1/manage')
990        self.assertFalse(
991            'upload_samplescanmanageupload' in self.browser.contents)
992        # File must be deleted first
993        self.browser.getControl(name='delete_samplescanmanageupload').click()
994        self.assertTrue(
995            'sample deleted' in self.browser.contents)
996        # Uploading a file which is bigger than 150k will raise an error
997        big_image = StringIO(open(SAMPLE_IMAGE, 'rb').read() * 75)
998        ctrl = self.browser.getControl(name='samplescanmanageupload')
999        file_ctrl = ctrl.mech_control
1000        file_ctrl.add_file(big_image, filename='my_sample_scan.jpg')
1001        self.browser.getControl(
1002            name='upload_samplescanmanageupload').click()
1003        self.assertTrue(
1004            'Uploaded file is too big' in self.browser.contents)
1005        # We do not rely on filename extensions given by uploaders
1006        image = open(SAMPLE_IMAGE, 'rb') # a jpg-file
1007        ctrl = self.browser.getControl(name='samplescanmanageupload')
1008        file_ctrl = ctrl.mech_control
1009        # Tell uploaded file is bmp
1010        file_ctrl.add_file(image, filename='my_sample_scan.bmp')
1011        self.browser.getControl(
1012            name='upload_samplescanmanageupload').click()
1013        self.assertTrue(
1014            # jpg file was recognized
1015            'File sample.jpg uploaded.' in self.browser.contents)
1016        # Delete file again
1017        self.browser.getControl(name='delete_samplescanmanageupload').click()
1018        self.assertTrue(
1019            'sample deleted' in self.browser.contents)
1020        # File names must meet several conditions
1021        bmp_image = open(SAMPLE_IMAGE_BMP, 'rb')
1022        ctrl = self.browser.getControl(name='samplescanmanageupload')
1023        file_ctrl = ctrl.mech_control
1024        file_ctrl.add_file(bmp_image, filename='my_sample_scan.bmp')
1025        self.browser.getControl(
1026            name='upload_samplescanmanageupload').click()
1027        self.assertTrue('Only the following extensions are allowed'
1028            in self.browser.contents)
1029
1030    def test_verify_document(self):
1031        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1032        self.browser.open(self.customer_path + '/documents/DOC1/manage')
1033        image = open(SAMPLE_IMAGE, 'rb')
1034        ctrl = self.browser.getControl(name='samplescanmanageupload')
1035        file_ctrl = ctrl.mech_control
1036        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1037        self.browser.getControl(
1038            name='upload_samplescanmanageupload').click()
1039        IWorkflowState(self.document).setState(SUBMITTED)
1040        # Only after verifying the document, sample_md5 is set
1041        self.assertEqual(
1042            getattr(self.document, 'sample_md5', None), None)
1043        self.browser.open(self.documents_path + '/DOC1/trigtrans')
1044        self.browser.getControl(name="transition").value = ['verify']
1045        self.browser.getControl("Apply now").click()
1046        self.assertEqual(
1047            getattr(self.document, 'sample_md5', None),
1048                    '1d1ab893e87c240afb2104d61ddfe180')
1049
1050    def test_manage_upload_pdf_file(self):
1051        # Managers can upload a file via the DocumentManageFormPage
1052        # The image is stored even if form has errors
1053        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1054        self.browser.open(self.customer_path + '/documents')
1055        self.browser.getControl("Add document").click()
1056        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
1057        self.browser.getControl(name="form.title").value = 'My PDF Document'
1058        self.browser.getControl("Add document").click()
1059        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
1060        self.browser.open(self.documents_path + '/%s/manage' % docid)
1061        # Create a pseudo image file and select it to be uploaded
1062        image = open(SAMPLE_IMAGE, 'rb')
1063        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1064        file_ctrl = ctrl.mech_control
1065        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1066        self.browser.getControl(
1067            name='upload_pdfscanmanageupload').click()
1068        self.assertTrue(
1069            'pdf file extension expected' in self.browser.contents)
1070        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1071        file_ctrl = ctrl.mech_control
1072        file_ctrl.add_file(image, filename='my_sample_scan.pdf')
1073        self.browser.getControl(
1074            name='upload_pdfscanmanageupload').click()
1075        self.assertTrue(
1076            'Could not determine file type' in self.browser.contents)
1077        pdf = open(SAMPLE_PDF, 'rb')
1078        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1079        file_ctrl = ctrl.mech_control
1080        file_ctrl.add_file(pdf, filename='my_sample_scan.pdf')
1081        self.browser.getControl(
1082            name='upload_pdfscanmanageupload').click()
1083        self.assertTrue(
1084            'href="http://localhost/app/customers/K1000000/documents/%s/sample.pdf">PDF File</a>'
1085            % docid in self.browser.contents)
1086        # Browsing the link shows a real pdf
1087        self.browser.open('sample.pdf')
1088        self.assertEqual(
1089            self.browser.headers['content-type'], 'application/pdf')
1090
1091    def test_view_slips(self):
1092        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1093        # Officers can open the document overview
1094        self.browser.open(self.customer_path + '/documents')
1095        self.browser.getLink("Download documents overview").click()
1096        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1097        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1098        path = os.path.join(samples_dir(), 'documents_overview_slip.pdf')
1099        open(path, 'wb').write(self.browser.contents)
1100        print "Sample PDF overview_slip.pdf written to %s" % path
1101        # Officers can open document slips which shows a thumbnail of
1102        # the jpeg file attached.
1103        file_id = IFileStoreNameChooser(self.document).chooseName(attr='sample.jpg')
1104        fs = ExtFileStore(root=self.dc_root)
1105        jpegfile = open(SAMPLE_IMAGE, 'rb')
1106        fs.createFile(file_id, jpegfile)
1107        self.browser.open(self.customer_path + '/documents/DOC1')
1108        self.browser.getLink("Download document slip").click()
1109        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1110        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1111        path = os.path.join(samples_dir(), 'document_slip.pdf')
1112        open(path, 'wb').write(self.browser.contents)
1113        print "Sample document_slip.pdf written to %s" % path
1114        # Officers can open merged pdf document slips
1115        pdfdocument = createObject('waeup.CustomerPDFDocument')
1116        pdfdocument.title = u'My first document'
1117        self.customer['documents'].addDocument(pdfdocument)
1118        # Add pdf file
1119        file_id = IFileStoreNameChooser(pdfdocument).chooseName(attr='sample.pdf')
1120        fs = ExtFileStore(root=self.dc_root)
1121        pdffile = open(SAMPLE_PDF, 'rb')
1122        fs.createFile(file_id, pdffile)
1123        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
1124        self.browser.open(self.customer_path + '/documents/' + docid)
1125        self.browser.getLink("Download document slip").click()
1126        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1127        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1128        path = os.path.join(samples_dir(), 'pdfdocument_slip.pdf')
1129        open(path, 'wb').write(self.browser.contents)
1130        print "Sample pdfdocument_slip.pdf written to %s" % path
1131
1132    def test_get_setmd5_file(self):
1133        # A proper file name chooser is registered for customer documents.
1134        # This is not a UI test. It's just a functional test.
1135        file_id = IFileStoreNameChooser(self.document).chooseName(attr='sample')
1136        fs = ExtFileStore(root=self.dc_root)
1137        fs.createFile(file_id, StringIO('my sample 1'))
1138        result = fs.getFileByContext(self.document, attr='sample')
1139        self.assertEqual(file_id, '__file-customerdocument__01000/K1000000/sample_DOC1_K1000000')
1140        self.assertEqual(result.read(), 'my sample 1')
1141        self.assertEqual(self.document.connected_files[0][1].read(), 'my sample 1')
1142        self.document.setMD5()
1143        self.assertEqual(self.document.sample_md5, 'a406995ee8eb6772bacf51aa4b0caa24')
1144        return
1145
1146
1147class ContractUITests(CustomersFullSetup):
1148    # Tests for contract related views and pages
1149
1150    def test_manage_contract(self):
1151        # Managers can access the pages of customer contractsconter
1152        # and can perform actions
1153        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1154        self.browser.open(self.customer_path)
1155        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1156        self.assertEqual(self.browser.url, self.customer_path)
1157        self.browser.open(self.customer_path)
1158        self.browser.getLink("Contracts").click()
1159        self.browser.getControl("Add contract").click()
1160        self.browser.getControl(name="contype").value = ['SampleContract']
1161        self.browser.getControl(name="form.title").value = 'My Sample Contract'
1162        self.browser.getControl("Add contract").click()
1163        self.assertTrue('Sample Contract added.' in self.browser.contents)
1164        conid = [i for i in self.customer['contracts'].keys() if len(i) > 10][0]
1165        contract = self.customer['contracts'][conid]
1166
1167        # Contract can be edited
1168        self.browser.getLink(conid).click()
1169        self.browser.getLink("Manage").click()
1170        self.browser.getControl(name="form.product_object").value = ['SAM']
1171        self.browser.getControl(name="form.title").value = 'My second contract'
1172        self.browser.getControl("Save").click()
1173        self.assertTrue('Form has been saved.' in self.browser.contents)
1174        self.browser.getLink("View").click()
1175        self.assertEqual(self.browser.url, self.contracts_path + '/%s/index' % conid)
1176
1177        # Transitions can be performed
1178        self.browser.getLink("Transition").click()
1179        self.browser.getControl(name="transition").value = ['submit']
1180        self.browser.getControl("Apply now").click()
1181        self.browser.getLink("Transition").click()
1182        self.browser.getControl(name="transition").value = ['approve']
1183        self.browser.getControl("Apply now").click()
1184        self.assertEqual(contract.state, 'approved')
1185
1186        # Contracts can be removed
1187        self.browser.getLink("Contracts").click()
1188        ctrl = self.browser.getControl(name='val_id')
1189        ctrl.getControl(value=contract.contract_id).selected = True
1190        self.browser.getControl("Remove selected", index=0).click()
1191        self.assertTrue('Successfully removed' in self.browser.contents)
1192
1193        # All actions are being logged
1194        logfile = os.path.join(
1195            self.app['datacenter'].storage, 'logs', 'customers.log')
1196        logcontent = open(logfile).read()
1197        self.assertTrue(
1198            'INFO - zope.mgr - K1000000 - %s - Contract created' % conid
1199            in logcontent)
1200        self.assertTrue(
1201            'INFO - zope.mgr - customers.browser.ContractAddFormPage '
1202            '- K1000000 - added: Sample Contract %s'
1203            % contract.contract_id in logcontent)
1204        self.assertTrue(
1205            'INFO - zope.mgr - customers.browser.ContractManageFormPage '
1206            '- K1000000 - %s - saved: title' % conid
1207            in logcontent)
1208        self.assertTrue(
1209            'INFO - zope.mgr - K1000000 - %s - Submitted for approval' % conid
1210            in logcontent)
1211        self.assertTrue(
1212            'INFO - zope.mgr - K1000000 - %s - Approved' % conid
1213            in logcontent)
1214        self.assertTrue(
1215            'INFO - zope.mgr - customers.browser.ContractsManageFormPage '
1216            '- K1000000 - removed: %s' % conid
1217            in logcontent)
1218
1219    def test_edit_sample_contract(self):
1220        # We add a second product.
1221        product = createObject('waeup.Product')
1222        product.product_id = u'LIC'
1223        product.title = u'Our License Product'
1224        product.contract_category = u'license'
1225        self.app['products'].addProduct(product)
1226        # Customers can manage contracts under certain conditions
1227        self.browser.open(self.login_path)
1228        self.browser.getControl(name="form.login").value = self.customer_id
1229        self.browser.getControl(name="form.password").value = 'cpwd'
1230        self.browser.getControl("Login").click()
1231        self.assertMatches(
1232            '...You logged in...', self.browser.contents)
1233        self.browser.getLink("Contracts").click()
1234        self.browser.getControl("Add contract").click()
1235        self.browser.getControl(name="contype").value = ['SampleContract']
1236        self.browser.getControl(name="form.title").value = 'My Sample Contract'
1237        self.browser.getControl("Add contract").click()
1238        self.assertTrue('Sample Contract added.' in self.browser.contents)
1239        conid = [i for i in self.customer['contracts'].keys() if len(i) > 10][0]
1240        contract = self.customer['contracts'][conid]
1241        # Contract can be edited ...
1242        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1243        #self.browser.getLink("Edit").click()
1244        self.assertTrue('The requested form is locked' in self.browser.contents)
1245        # Customer is in wrong state
1246        IWorkflowState(self.customer).setState(APPROVED)
1247        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1248        self.browser.getControl(name="form.title").value = 'My second contract'
1249        # SAM is in the correct contract_category ...
1250        self.assertTrue('<option value="SAM">' in self.browser.contents)
1251        # ... but NOTSAM not.
1252        self.assertFalse('<option value="LIC">' in self.browser.contents)
1253        # So far last_product_id is None.
1254        self.assertTrue(self.customer['contracts'][conid].last_product_id is None)
1255        self.browser.getControl(name="form.product_object").value = ['SAM']
1256        self.browser.getControl("Save").click()
1257        # Document is a required field on edit form page.
1258        self.assertTrue('Document: <span class="error">Required input is missing.</span>'
1259            in self.browser.contents)
1260        # But our document can't be selected because it's not submitted
1261        self.assertFalse('My first document' in self.browser.contents)
1262        IWorkflowState(self.document).setState(SUBMITTED)
1263        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1264        self.browser.getControl(name="form.product_object").value = ['SAM']
1265        self.browser.getControl(name="form.document_object").value = ['DOC1']
1266        self.browser.getControl(name="form.title").value = 'My second contract'
1267        self.browser.getControl("Save").click()
1268        # After saving the form, last_product_id and other attributes are set
1269        self.assertTrue('Form has been saved.' in self.browser.contents)
1270        self.assertEqual(self.customer['contracts'][conid].last_product_id, 'SAM')
1271        self.assertEqual(contract.title, 'My second contract')
1272        self.assertEqual(contract.product_object, self.product)
1273        self.assertEqual(contract.document_object, self.document)
1274        # Saving the form again does not unset last_product_id
1275        self.browser.getControl(name="form.title").value = 'My third contract'
1276        self.browser.getControl("Save").click()
1277        self.assertEqual(self.customer['contracts'][conid].last_product_id, 'SAM')
1278        self.assertTrue('Form has been saved.' in self.browser.contents)
1279        self.browser.getLink("View").click()
1280        self.assertEqual(self.browser.url, self.contracts_path + '/%s/index' % conid)
1281        # An href attribute is referring to the document and product objects
1282        self.assertTrue('<a href="http://localhost/app/products/SAM">SAM -'
1283            in self.browser.contents)
1284        self.assertTrue(
1285            '<a href="http://localhost/app/customers/K1000000/documents/DOC1">DOC1 -'
1286            in self.browser.contents)
1287        # Customer can submit the form. The form is also saved.
1288        self.browser.getLink("Edit").click()
1289        self.browser.getControl(name="form.title").value = 'My fourth contract'
1290        self.browser.getControl("Apply now").click()
1291        self.assertEqual(contract.title, 'My fourth contract')
1292        self.assertEqual(contract.state, 'submitted')
1293        self.assertTrue('Contract State: submitted for approval' in self.browser.contents)
1294        # Customer can't edit the contract once it has been submitted
1295        self.browser.open(self.contracts_path + '/%s/edit' % conid)
1296        self.assertTrue('The requested form is locked' in self.browser.contents)
1297
1298    def test_view_slips(self):
1299        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1300        # Officers can open the contract overview
1301        self.browser.open(self.customer_path + '/contracts')
1302        self.browser.getLink("Download contracts overview").click()
1303        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1304        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1305        path = os.path.join(samples_dir(), 'contracts_overview_slip.pdf')
1306        open(path, 'wb').write(self.browser.contents)
1307        print "Sample PDF overview_slip.pdf written to %s" % path
1308        # Officers can open contract slips.
1309        # First we add a submitted document and a product.
1310        IWorkflowState(self.document).setState(SUBMITTED)
1311        self.contract.document_object = self.document
1312        self.contract.product_object = self.product
1313        self.browser.open(self.customer_path + '/contracts/CON1')
1314        self.browser.getLink("Download contract slip").click()
1315        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1316        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1317        path = os.path.join(samples_dir(), 'contract_slip.pdf')
1318        open(path, 'wb').write(self.browser.contents)
1319        print "Sample contract_slip.pdf written to %s" % path
1320
1321    def test_contract_approval(self):
1322        # This is not a UI test. It just a functional test.
1323        self.assertRaises(ConstraintNotSatisfied,
1324            self.contract.document_object, self.document)
1325        # Document must be at least submitted
1326        IWorkflowState(self.document).setState('submitted')
1327        self.contract.document_object = self.document
1328        IWorkflowState(self.contract).setState('submitted')
1329        self.assertRaises(InvalidTransitionError,
1330            IWorkflowInfo(self.contract).fireTransition, 'approve')
1331        # Document must be verified for the approval of contracts
1332        IWorkflowState(self.document).setState('verified')
1333        IWorkflowInfo(self.contract).fireTransition('approve')
1334        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
1335
1336    def test_contract_approval_in_UI(self):
1337        # Now let's see what the UI says why trying to approve a contract
1338        # with unverified documents.
1339        IWorkflowState(self.document).setState('submitted')
1340        self.contract.document_object = self.document
1341        IWorkflowState(self.contract).setState('submitted')
1342        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1343        self.browser.open(self.contracts_path + '/CON1/trigtrans')
1344        self.browser.getControl(name="transition").value = ['approve']
1345        self.browser.getControl("Apply now").click()
1346        # InvalidTransitionError is catched
1347        self.assertTrue(
1348            '<div class="alert alert-warning">Attached documents must be verified first.</div>'
1349            in self.browser.contents)
1350        self.browser.open(self.contracts_path + '/CON1/trigtrans')
1351        IWorkflowState(self.document).setState('verified')
1352        self.browser.getControl(name="transition").value = ['approve']
1353        self.browser.getControl("Apply now").click()
1354        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
Note: See TracBrowser for help on using the repository browser.