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

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

Make necessary changes in root and in customer browser test.

Add plugin to create documents folder.

  • Property svn:keywords set to Id
File size: 66.1 KB
Line 
1## $Id: test_browser.py 12207 2014-12-13 07:30:38Z 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.documents.workflow 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.customer['documents'].addDocument(self.document)
123        self.contract = createObject('waeup.SampleContract')
124        self.contract.title = u'My first contract'
125        self.customer['contracts'].addContract(self.contract)
126
127        # Set password
128        IUserAccount(
129            self.app['customers'][self.customer_id]).setPassword('cpwd')
130
131        self.login_path = 'http://localhost/app/login'
132        self.container_path = 'http://localhost/app/customers'
133        self.manage_container_path = self.container_path + '/@@manage'
134        self.add_customer_path = self.container_path + '/addcustomer'
135        self.customer_path = self.container_path + '/' + self.customer_id
136        self.manage_customer_path = self.customer_path + '/manage_base'
137        self.trigtrans_path = self.customer_path + '/trigtrans'
138        self.history_path = self.customer_path + '/history'
139        self.documents_path = self.customer_path + '/documents'
140        self.contracts_path = self.customer_path + '/contracts'
141
142        self.app['configuration'].carry_over = True
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 record").click()
198        self.assertTrue('Customer record 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("Save").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("Save").click()
381        self.browser.getControl(name="transition").value = ['request']
382        self.browser.getControl("Save").click()
383        self.browser.getControl(name="transition").value = ['reject']
384        self.browser.getControl("Save").click()
385        self.browser.getControl(name="transition").value = ['request']
386        self.browser.getControl("Save").click()
387        self.browser.getControl(name="transition").value = ['approve']
388        self.browser.getControl("Save").click()
389        self.browser.getControl(name="transition").value = ['reset1']
390        self.browser.getControl("Save").click()
391        return
392
393    def test_manage_import(self):
394        # Managers can import customer data files
395        datacenter_path = 'http://localhost/app/datacenter'
396        # Prepare a csv file for customers
397        open('customers.csv', 'wb').write(
398"""firstname,lastname,reg_number,date_of_birth,email,phone,sex,password
399Aaren,Pieri,1,1990-01-02,aa@aa.ng,1234,m,mypwd1
400Claus,Finau,2,1990-01-03,aa@aa.ng,1234,m,mypwd1
401Brit,Berson,2,1990-01-04,aa@aa.ng,1234,m,mypwd1
402""")
403        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
404        self.browser.open(datacenter_path)
405        self.browser.getLink('Upload data').click()
406        filecontents = StringIO(open('customers.csv', 'rb').read())
407        filewidget = self.browser.getControl(name='uploadfile:file')
408        filewidget.add_file(filecontents, 'text/plain', 'customers.csv')
409        self.browser.getControl(name='SUBMIT').click()
410        self.browser.getLink('Process data').click()
411        button = lookup_submit_value(
412            'select', 'customers_zope.mgr.csv', self.browser)
413        button.click()
414        importerselect = self.browser.getControl(name='importer')
415        modeselect = self.browser.getControl(name='mode')
416        importerselect.getControl('Customer Processor').selected = True
417        modeselect.getControl(value='create').selected = True
418        self.browser.getControl('Proceed to step 3').click()
419        self.assertTrue('Header fields OK' in self.browser.contents)
420        self.browser.getControl('Perform import').click()
421        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
422        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
423        self.assertTrue('Batch processing finished' in self.browser.contents)
424
425        # The customers are properly indexed and we can
426        # thus find a customer in  the department
427        self.browser.open(self.manage_container_path)
428        # We can search for a new customer by name ...
429        self.browser.getControl(name="searchtype").value = ['fullname']
430        self.browser.getControl(name="searchterm").value = 'Claus'
431        self.browser.getControl("Find customer(s)").click()
432        self.assertTrue('Claus Finau' in self.browser.contents)
433        # ... and check if the imported password has been properly set
434        ctrl = self.browser.getControl(name='entries')
435        value = ctrl.options[0]
436        claus = self.app['customers'][value]
437        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
438        return
439
440    def test_activate_deactivate_buttons(self):
441        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
442        self.browser.open(self.customer_path)
443        self.browser.getLink("Deactivate").click()
444        self.assertTrue(
445            'Customer account has been deactivated.' in self.browser.contents)
446        self.assertTrue(
447            'Base Data (account deactivated)' in self.browser.contents)
448        self.assertTrue(self.customer.suspended)
449        self.browser.getLink("Activate").click()
450        self.assertTrue(
451            'Customer account has been activated.' in self.browser.contents)
452        self.assertFalse(
453            'Base Data (account deactivated)' in self.browser.contents)
454        self.assertFalse(self.customer.suspended)
455        # History messages have been added ...
456        self.browser.getLink("History").click()
457        self.assertTrue(
458            'Customer account deactivated by Manager<br />' in self.browser.contents)
459        self.assertTrue(
460            'Customer account activated by Manager<br />' in self.browser.contents)
461        # ... and actions have been logged.
462        logfile = os.path.join(
463            self.app['datacenter'].storage, 'logs', 'customers.log')
464        logcontent = open(logfile).read()
465        self.assertTrue('zope.mgr - customers.browser.CustomerDeactivatePage - '
466                        'K1000000 - account deactivated' in logcontent)
467        self.assertTrue('zope.mgr - customers.browser.CustomerActivatePage - '
468                        'K1000000 - account activated' in logcontent)
469
470
471    def test_login_as_customer(self):
472        # CustomerImpersonators can login as customer
473        # Create clearance officer
474        self.app['users'].addUser('mrofficer', 'mrofficersecret')
475        self.app['users']['mrofficer'].email = 'mrofficer@foo.ng'
476        self.app['users']['mrofficer'].title = 'Harry Actor'
477        prmglobal = IPrincipalRoleManager(self.app)
478        prmglobal.assignRoleToPrincipal('waeup.CustomerImpersonator', 'mrofficer')
479        prmglobal.assignRoleToPrincipal('waeup.CustomersManager', 'mrofficer')
480        # Login as customer impersonator
481        self.browser.open(self.login_path)
482        self.browser.getControl(name="form.login").value = 'mrofficer'
483        self.browser.getControl(name="form.password").value = 'mrofficersecret'
484        self.browser.getControl("Login").click()
485        self.assertMatches('...You logged in...', self.browser.contents)
486        self.browser.open(self.customer_path)
487        self.browser.getLink("Login as").click()
488        self.browser.getControl("Set password now").click()
489        temp_password = self.browser.getControl(name='form.password').value
490        self.browser.getControl("Login now").click()
491        self.assertMatches(
492            '...You successfully logged in as...', self.browser.contents)
493        # We are logged in as customer and can see the 'My Data' tab
494        self.assertMatches(
495            '...<a href="#" class="dropdown-toggle" data-toggle="dropdown">...',
496            self.browser.contents)
497        self.assertMatches(
498            '...My Data...',
499            self.browser.contents)
500        self.browser.getLink("Logout").click()
501        # The customer can't login with the original password ...
502        self.browser.open(self.login_path)
503        self.browser.getControl(name="form.login").value = self.customer_id
504        self.browser.getControl(name="form.password").value = 'cpwd'
505        self.browser.getControl("Login").click()
506        self.assertMatches(
507            '...Your account has been temporarily deactivated...',
508            self.browser.contents)
509        # ... but with the temporary password
510        self.browser.open(self.login_path)
511        self.browser.getControl(name="form.login").value = self.customer_id
512        self.browser.getControl(name="form.password").value = temp_password
513        self.browser.getControl("Login").click()
514        self.assertMatches('...You logged in...', self.browser.contents)
515        # Creation of temp_password is properly logged
516        logfile = os.path.join(
517            self.app['datacenter'].storage, 'logs', 'customers.log')
518        logcontent = open(logfile).read()
519        self.assertTrue(
520            'mrofficer - customers.browser.LoginAsCustomerStep1 - K1000000 - '
521            'temp_password generated: %s' % temp_password in logcontent)
522
523
524class CustomerUITests(CustomersFullSetup):
525    # Tests for Customer class views and pages
526
527    def test_customer_change_password(self):
528        # Customers can change the password
529        self.customer.personal_updated = datetime.utcnow()
530        self.browser.open(self.login_path)
531        self.browser.getControl(name="form.login").value = self.customer_id
532        self.browser.getControl(name="form.password").value = 'cpwd'
533        self.browser.getControl("Login").click()
534        self.assertEqual(self.browser.url, self.customer_path)
535        self.assertTrue('You logged in' in self.browser.contents)
536        # Change password
537        self.browser.getLink("Change password").click()
538        self.browser.getControl(name="change_password").value = 'pw'
539        self.browser.getControl(
540            name="change_password_repeat").value = 'pw'
541        self.browser.getControl("Save").click()
542        self.assertTrue('Password must have at least' in self.browser.contents)
543        self.browser.getControl(name="change_password").value = 'new_password'
544        self.browser.getControl(
545            name="change_password_repeat").value = 'new_passssword'
546        self.browser.getControl("Save").click()
547        self.assertTrue('Passwords do not match' in self.browser.contents)
548        self.browser.getControl(name="change_password").value = 'new_password'
549        self.browser.getControl(
550            name="change_password_repeat").value = 'new_password'
551        self.browser.getControl("Save").click()
552        self.assertTrue('Password changed' in self.browser.contents)
553        # We are still logged in. Changing the password hasn't thrown us out.
554        self.browser.getLink("Base Data").click()
555        self.assertEqual(self.browser.url, self.customer_path)
556        # We can logout
557        self.browser.getLink("Logout").click()
558        self.assertTrue('You have been logged out' in self.browser.contents)
559        self.assertEqual(self.browser.url, 'http://localhost/app/index')
560        # We can login again with the new password
561        self.browser.getLink("Login").click()
562        self.browser.open(self.login_path)
563        self.browser.getControl(name="form.login").value = self.customer_id
564        self.browser.getControl(name="form.password").value = 'new_password'
565        self.browser.getControl("Login").click()
566        self.assertEqual(self.browser.url, self.customer_path)
567        self.assertTrue('You logged in' in self.browser.contents)
568        return
569
570    def test_customer_upload_passport(self):
571        # Customer cant login if their password is not set
572        IWorkflowInfo(self.customer).fireTransition('start')
573        self.browser.open(self.login_path)
574        self.browser.getControl(name="form.login").value = self.customer_id
575        self.browser.getControl(name="form.password").value = 'cpwd'
576        self.browser.getControl("Login").click()
577        self.assertMatches(
578            '...You logged in...', self.browser.contents)
579        # Admitted customer can upload a passport picture
580        self.browser.getLink("Change portrait").click()
581        ctrl = self.browser.getControl(name='passporteditupload')
582        file_obj = open(SAMPLE_IMAGE, 'rb')
583        file_ctrl = ctrl.mech_control
584        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
585        self.browser.getControl(
586            name='upload_passporteditupload').click()
587        self.assertTrue(
588            'src="http://localhost/app/customers/K1000000/passport.jpg"'
589            in self.browser.contents)
590
591    def test_customer_baseedit(self):
592        # Customers can change the password
593        self.customer.personal_updated = datetime.utcnow()
594        self.browser.open(self.login_path)
595        self.browser.getControl(name="form.login").value = self.customer_id
596        self.browser.getControl(name="form.password").value = 'cpwd'
597        self.browser.getControl("Login").click()
598        self.assertEqual(self.browser.url, self.customer_path)
599        self.assertTrue('You logged in' in self.browser.contents)
600        self.browser.getLink("Edit").click()
601        self.browser.getControl(name="form.email").value = 'new_email@aa.ng'
602        self.browser.getControl("Save").click()
603        self.assertMatches('...Form has been saved...',
604                           self.browser.contents)
605        # Customer can view history
606        self.browser.getLink("History").click()
607        self.assertMatches('...Customer record created by system...',
608            self.browser.contents)
609
610    def test_customer_login(self):
611        # Customer cant login if their password is not set
612        self.customer.password = None
613        self.browser.open(self.login_path)
614        self.browser.getControl(name="form.login").value = self.customer_id
615        self.browser.getControl(name="form.password").value = 'cpwd'
616        self.browser.getControl("Login").click()
617        self.assertTrue(
618            'You entered invalid credentials.' in self.browser.contents)
619        # We set the password again
620        IUserAccount(
621            self.app['customers'][self.customer_id]).setPassword('cpwd')
622        # Customers can't login if their account is suspended/deactivated
623        self.customer.suspended = True
624        self.browser.open(self.login_path)
625        self.browser.getControl(name="form.login").value = self.customer_id
626        self.browser.getControl(name="form.password").value = 'cpwd'
627        self.browser.getControl("Login").click()
628        self.assertMatches(
629            '...<div class="alert alert-warning">'
630            'Your account has been deactivated.</div>...', self.browser.contents)
631        # If suspended_comment is set this message will be flashed instead
632        self.customer.suspended_comment = u'Aetsch baetsch!'
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.assertMatches(
637            '...<div class="alert alert-warning">Aetsch baetsch!</div>...',
638            self.browser.contents)
639        self.customer.suspended = False
640        # Customers can't login if a temporary password has been set and
641        # is not expired
642        self.app['customers'][self.customer_id].setTempPassword(
643            'anybody', 'temp_cpwd')
644        self.browser.open(self.login_path)
645        self.browser.getControl(name="form.login").value = self.customer_id
646        self.browser.getControl(name="form.password").value = 'cpwd'
647        self.browser.getControl("Login").click()
648        self.assertMatches(
649            '...Your account has been temporarily deactivated...',
650            self.browser.contents)
651        # The customer can login with the temporary password
652        self.browser.open(self.login_path)
653        self.browser.getControl(name="form.login").value = self.customer_id
654        self.browser.getControl(name="form.password").value = 'temp_cpwd'
655        self.browser.getControl("Login").click()
656        self.assertMatches(
657            '...You logged in...', self.browser.contents)
658        # Customer can view the base data
659        self.browser.open(self.customer_path)
660        self.assertEqual(self.browser.headers['Status'], '200 Ok')
661        self.assertEqual(self.browser.url, self.customer_path)
662        # When the password expires ...
663        delta = timedelta(minutes=11)
664        self.app['customers'][self.customer_id].temp_password[
665            'timestamp'] = datetime.utcnow() - delta
666        self.app['customers'][self.customer_id]._p_changed = True
667        # ... the customer will be automatically logged out
668        self.assertRaises(
669            Unauthorized, self.browser.open, self.customer_path)
670        # Then the customer can login with the original password
671        self.browser.open(self.login_path)
672        self.browser.getControl(name="form.login").value = self.customer_id
673        self.browser.getControl(name="form.password").value = 'cpwd'
674        self.browser.getControl("Login").click()
675        self.assertMatches(
676            '...You logged in...', self.browser.contents)
677
678    def test_change_password_request(self):
679        self.browser.open('http://localhost/app/changepw')
680        self.browser.getControl(name="form.identifier").value = '123'
681        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
682        self.browser.getControl("Send login credentials").click()
683        self.assertTrue('An email with' in self.browser.contents)
684
685class CustomerRegistrationTests(CustomersFullSetup):
686    # Tests for customer registration
687
688    layer = FunctionalLayer
689
690    def test_request_pw(self):
691        # Customer with wrong number can't be found.
692        self.browser.open('http://localhost/app/requestpw')
693        self.browser.getControl(name="form.firstname").value = 'Anna'
694        self.browser.getControl(name="form.number").value = 'anynumber'
695        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
696        self.browser.getControl("Send login credentials").click()
697        self.assertTrue('No customer record found.'
698            in self.browser.contents)
699        # Anonymous is not informed that firstname verification failed.
700        # It seems that the record doesn't exist.
701        self.browser.open('http://localhost/app/requestpw')
702        self.browser.getControl(name="form.firstname").value = 'Johnny'
703        self.browser.getControl(name="form.number").value = '123'
704        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
705        self.browser.getControl("Send login credentials").click()
706        self.assertTrue('No customer record found.'
707            in self.browser.contents)
708        # Even with the correct firstname we can't register if a
709        # password has been set and used.
710        self.browser.getControl(name="form.firstname").value = 'Anna'
711        self.browser.getControl(name="form.number").value = '123'
712        self.browser.getControl("Send login credentials").click()
713        self.assertTrue('Your password has already been set and used.'
714            in self.browser.contents)
715        self.browser.open('http://localhost/app/requestpw')
716        self.app['customers'][self.customer_id].password = None
717        # The firstname field, used for verification, is not case-sensitive.
718        self.browser.getControl(name="form.firstname").value = 'aNNa'
719        self.browser.getControl(name="form.number").value = '123'
720        self.browser.getControl(name="form.email").value = 'new@yy.zz'
721        self.browser.getControl("Send login credentials").click()
722        # Yeah, we succeded ...
723        self.assertTrue('Your request was successful.'
724            in self.browser.contents)
725        # ... and  customer can be found in the catalog via the email address
726        cat = queryUtility(ICatalog, name='customers_catalog')
727        results = list(
728            cat.searchResults(
729            email=('new@yy.zz', 'new@yy.zz')))
730        self.assertEqual(self.customer,results[0])
731        logfile = os.path.join(
732            self.app['datacenter'].storage, 'logs', 'main.log')
733        logcontent = open(logfile).read()
734        self.assertTrue('zope.anybody - customers.browser.CustomerRequestPasswordPage - '
735                        '123 (K1000000) - new@yy.zz' in logcontent)
736        return
737
738    def test_create_account(self):
739        # Customer with wrong number can't be found.
740        self.browser.open('http://localhost/app/createaccount')
741        self.browser.getControl(name="form.firstname").value = 'Ruben'
742        self.browser.getControl(name="form.lastname").value = 'Gonzales'
743        self.browser.getControl(name="form.email").value = 'newcustomer@xx.zz'
744        self.browser.getControl("Send login credentials").click()
745        self.assertTrue('Your request was successful.'
746            in self.browser.contents)
747        # ... and  customer can be found in the catalog via the email address
748        cat = queryUtility(ICatalog, name='customers_catalog')
749        results = list(
750            cat.searchResults(
751            email=('newcustomer@xx.zz', 'newcustomer@xx.zz')))
752        self.assertEqual(self.app['customers']['K1000001'], results[0])
753        self.assertEqual(self.app['customers']['K1000001'].firstname, 'Ruben')
754        self.assertEqual(self.app['customers']['K1000001'].lastname, 'Gonzales')
755        logfile = os.path.join(
756            self.app['datacenter'].storage, 'logs', 'main.log')
757        logcontent = open(logfile).read()
758        self.assertTrue('zope.anybody - customers.browser.CustomerCreateAccountPage - '
759                        'K1000001 - newcustomer@xx.zz' in logcontent)
760        return
761
762class CustomerDataExportTests(CustomersFullSetup, FunctionalAsyncTestCase):
763    # Tests for CustomersContainer class views and pages
764
765    layer = FunctionalLayer
766
767    def wait_for_export_job_completed(self):
768        # helper function waiting until the current export job is completed
769        manager = getUtility(IJobManager)
770        job_id = self.app['datacenter'].running_exports[0][0]
771        job = manager.get(job_id)
772        wait_for_result(job)
773        return job_id
774
775    def test_datacenter_export(self):
776        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
777        self.browser.open('http://localhost/app/datacenter/@@export')
778        self.browser.getControl(name="exporter").value = ['customers']
779        self.browser.getControl("Create CSV file").click()
780
781        # When the job is finished and we reload the page...
782        job_id = self.wait_for_export_job_completed()
783        # ... the csv file can be downloaded ...
784        self.browser.open('http://localhost/app/datacenter/@@export')
785        self.browser.getLink("Download").click()
786        self.assertEqual(self.browser.headers['content-type'],
787            'text/csv; charset=UTF-8')
788        self.assertTrue(
789            'filename="WAeUP.Ikoba_customers_%s.csv' % job_id in
790            self.browser.headers['content-disposition'])
791        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
792        job_id = self.app['datacenter'].running_exports[0][0]
793        # ... and discarded
794        self.browser.open('http://localhost/app/datacenter/@@export')
795        self.browser.getControl("Discard").click()
796        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
797        # Creation, downloading and discarding is logged
798        logfile = os.path.join(
799            self.app['datacenter'].storage, 'logs', 'datacenter.log')
800        logcontent = open(logfile).read()
801        self.assertTrue(
802            'zope.mgr - browser.pages.ExportCSVPage - exported: '
803            'customers, job_id=%s'
804            % job_id in logcontent
805            )
806        self.assertTrue(
807            'zope.mgr - browser.pages.ExportCSVView - downloaded: '
808            'WAeUP.Ikoba_customers_%s.csv, job_id=%s'
809            % (job_id, job_id) in logcontent
810            )
811        self.assertTrue(
812            'zope.mgr - browser.pages.ExportCSVPage - discarded: '
813            'job_id=%s' % job_id in logcontent
814            )
815
816
817class DocumentUITests(CustomersFullSetup):
818    # Tests for CustomerSampleDocument relates views and pages
819
820    def test_manage_document(self):
821        # Managers can access the pages of customer documentsconter
822        # and can perform actions
823        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
824        self.browser.open(self.customer_path)
825        self.assertEqual(self.browser.headers['Status'], '200 Ok')
826        self.assertEqual(self.browser.url, self.customer_path)
827        self.browser.open(self.customer_path)
828        self.browser.getLink("Documents", index=1).click()
829        self.browser.getLink("Add document").click()
830        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
831        self.browser.getControl("Create document").click()
832        self.assertTrue('PDF Document created.' in self.browser.contents)
833        document = self.customer['documents']['d102']
834
835        # Document can be edited
836        self.browser.getLink("d102").click()
837        self.browser.getLink("Manage").click()
838        self.browser.getControl(name="form.title").value = 'My second doc'
839        self.browser.getControl("Save").click()
840        self.assertTrue('Form has been saved.' in self.browser.contents)
841        self.browser.getLink("View").click()
842        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
843
844        # Transitions can be performed
845        self.browser.getLink("Transition").click()
846        self.browser.getControl(name="transition").value = ['submit']
847        self.browser.getControl("Save").click()
848        # Document can only be verified if files have been uploaded before
849        self.browser.getControl(name="transition").value = ['verify']
850        self.browser.getControl("Save").click()
851        self.assertTrue('No file uploaded' in self.browser.contents)
852        self.assertEqual(document.state, 'submitted')
853        # We set state here manually (verification is tested in test_verify_document)
854        IWorkflowState(document).setState(VERIFIED)
855
856        # Manage button and form is no longer available
857        self.browser.open(self.documents_path + '/d102/index')
858        self.assertFalse(
859            'href="http://localhost/app/customers/K1000000/documents/d102/manage"'
860            in self.browser.contents)
861        self.browser.open(self.documents_path + '/d102/manage')
862        self.assertTrue(
863            'The requested form is locked (read-only)'
864            in self.browser.contents)
865
866        # Documents can be removed
867        self.browser.getLink("Documents", index=1).click()
868        ctrl = self.browser.getControl(name='val_id')
869        ctrl.getControl(value=document.document_id).selected = True
870        self.browser.getControl("Remove selected", index=0).click()
871        self.assertTrue('Successfully removed' in self.browser.contents)
872
873        # All actions are being logged
874        logfile = os.path.join(
875            self.app['datacenter'].storage, 'logs', 'customers.log')
876        logcontent = open(logfile).read()
877
878        self.assertTrue(
879            'INFO - zope.mgr - customers.browser.DocumentManageFormPage '
880            '- K1000000 - d102 - saved: title'
881            in logcontent)
882        self.assertTrue(
883            'INFO - zope.mgr - customers.browser.DocumentAddFormPage '
884            '- K1000000 - added: PDF Document %s'
885            % document.document_id in logcontent)
886        self.assertTrue(
887            'INFO - zope.mgr - customers.browser.DocumentsManageFormPage '
888            '- K1000000 - removed: %s'
889            % document.document_id in logcontent)
890
891    def test_edit_sample_document(self):
892        # Customers can manage documents under certain conditions
893        self.browser.open(self.login_path)
894        self.browser.getControl(name="form.login").value = self.customer_id
895        self.browser.getControl(name="form.password").value = 'cpwd'
896        self.browser.getControl("Login").click()
897        self.assertMatches(
898            '...You logged in...', self.browser.contents)
899        self.browser.getLink("Documents").click()
900        self.browser.getLink("Add document").click()
901        self.browser.getControl(name="doctype").value = ['CustomerSampleDocument']
902        self.browser.getControl("Create document").click()
903        self.assertTrue('Sample Document created.' in self.browser.contents)
904        document = self.customer['documents']['d102']
905
906        # Document can be edited ...
907        self.browser.getLink("d102").click()
908        self.browser.open(self.documents_path + '/d102/edit')
909        #self.browser.getLink("Edit").click()
910        self.assertTrue('The requested form is locked' in self.browser.contents)
911        # Customer is in wrong state
912        IWorkflowState(self.customer).setState(APPROVED)
913        self.browser.open(self.documents_path + '/d102/edit')
914        self.browser.getControl(name="form.title").value = 'My second doc'
915        self.browser.getControl("Save").click()
916        self.assertEqual(document.title, 'My second doc')
917        self.assertTrue('Form has been saved.' in self.browser.contents)
918        self.browser.getLink("View").click()
919        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
920        # Costumer can upload a document.
921        self.browser.getLink("Edit").click()
922        ctrl = self.browser.getControl(name='samplescaneditupload')
923        file_obj = open(SAMPLE_IMAGE, 'rb')
924        file_ctrl = ctrl.mech_control
925        file_ctrl.add_file(file_obj, filename='my_document.jpg')
926        self.browser.getControl(
927            name='upload_samplescaneditupload').click()
928        self.assertTrue(
929            'href="http://localhost/app/customers/K1000000/documents/d102/sample"'
930            in self.browser.contents)
931        # Costumer can submit the form. The form is also saved.
932        self.browser.getControl(name="form.title").value = 'My third doc'
933        self.browser.getControl("Final Submit").click()
934        self.assertEqual(document.title, 'My third doc')
935        self.assertEqual(document.state, 'submitted')
936        self.assertTrue('Document State: submitted for verification' in self.browser.contents)
937        # Customer can't edit the document once it has been submitted
938        self.browser.open(self.documents_path + '/d102/edit')
939        self.assertTrue('The requested form is locked' in self.browser.contents)
940
941    def test_manage_upload_sample_file(self):
942        # Managers can upload a file via the DocumentManageFormPage
943        # The image is stored even if form has errors
944        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
945        self.browser.open(self.customer_path + '/documents/d101/manage')
946        # Create a pseudo image file and select it to be uploaded
947        image = open(SAMPLE_IMAGE, 'rb')
948        ctrl = self.browser.getControl(name='samplescanmanageupload')
949        file_ctrl = ctrl.mech_control
950        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
951        # The Save action does not upload files
952        self.browser.getControl("Save").click() # submit form
953        self.assertFalse(
954            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
955            in self.browser.contents)
956        # ... but the correct upload submit button does
957        image = open(SAMPLE_IMAGE)
958        ctrl = self.browser.getControl(name='samplescanmanageupload')
959        file_ctrl = ctrl.mech_control
960        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
961        self.browser.getControl(
962            name='upload_samplescanmanageupload').click()
963        self.assertTrue(
964            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
965            in self.browser.contents)
966        # Browsing the link shows a real image
967        self.browser.open('sample')
968        self.assertEqual(
969            self.browser.headers['content-type'], 'image/jpeg')
970        self.assertEqual(len(self.browser.contents), 2787)
971        # We can't reupload a file. The existing file must be deleted first.
972        self.browser.open(self.customer_path + '/documents/d101/manage')
973        self.assertFalse(
974            'upload_samplescanmanageupload' in self.browser.contents)
975        # File must be deleted first
976        self.browser.getControl(name='delete_samplescanmanageupload').click()
977        self.assertTrue(
978            'sample deleted' in self.browser.contents)
979        # Uploading a file which is bigger than 150k will raise an error
980        big_image = StringIO(open(SAMPLE_IMAGE, 'rb').read() * 75)
981        ctrl = self.browser.getControl(name='samplescanmanageupload')
982        file_ctrl = ctrl.mech_control
983        file_ctrl.add_file(big_image, filename='my_sample_scan.jpg')
984        self.browser.getControl(
985            name='upload_samplescanmanageupload').click()
986        self.assertTrue(
987            'Uploaded file is too big' in self.browser.contents)
988        # We do not rely on filename extensions given by uploaders
989        image = open(SAMPLE_IMAGE, 'rb') # a jpg-file
990        ctrl = self.browser.getControl(name='samplescanmanageupload')
991        file_ctrl = ctrl.mech_control
992        # Tell uploaded file is bmp
993        file_ctrl.add_file(image, filename='my_sample_scan.bmp')
994        self.browser.getControl(
995            name='upload_samplescanmanageupload').click()
996        self.assertTrue(
997            # jpg file was recognized
998            'File sample.jpg uploaded.' in self.browser.contents)
999        # Delete file again
1000        self.browser.getControl(name='delete_samplescanmanageupload').click()
1001        self.assertTrue(
1002            'sample deleted' in self.browser.contents)
1003        # File names must meet several conditions
1004        bmp_image = open(SAMPLE_IMAGE_BMP, 'rb')
1005        ctrl = self.browser.getControl(name='samplescanmanageupload')
1006        file_ctrl = ctrl.mech_control
1007        file_ctrl.add_file(bmp_image, filename='my_sample_scan.bmp')
1008        self.browser.getControl(
1009            name='upload_samplescanmanageupload').click()
1010        self.assertTrue('Only the following extensions are allowed'
1011            in self.browser.contents)
1012
1013    def test_verify_document(self):
1014        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1015        self.browser.open(self.customer_path + '/documents/d101/manage')
1016        image = open(SAMPLE_IMAGE, 'rb')
1017        ctrl = self.browser.getControl(name='samplescanmanageupload')
1018        file_ctrl = ctrl.mech_control
1019        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1020        self.browser.getControl(
1021            name='upload_samplescanmanageupload').click()
1022        IWorkflowState(self.document).setState(SUBMITTED)
1023        # Only after verifying the document, sample_md5 is set
1024        self.assertEqual(
1025            getattr(self.document, 'sample_md5', None), None)
1026        self.browser.open(self.documents_path + '/d101/trigtrans')
1027        self.browser.getControl(name="transition").value = ['verify']
1028        self.browser.getControl("Save").click()
1029        self.assertEqual(
1030            getattr(self.document, 'sample_md5', None),
1031                    '1d1ab893e87c240afb2104d61ddfe180')
1032
1033    def test_manage_upload_pdf_file(self):
1034        # Managers can upload a file via the DocumentManageFormPage
1035        # The image is stored even if form has errors
1036        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1037        self.browser.open(self.customer_path + '/documents')
1038        self.browser.getLink("Add document").click()
1039        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
1040        self.browser.getControl("Create document").click()
1041        self.browser.open(self.documents_path + '/d102/manage')
1042        # Create a pseudo image file and select it to be uploaded
1043        image = open(SAMPLE_IMAGE, 'rb')
1044        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1045        file_ctrl = ctrl.mech_control
1046        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1047        self.browser.getControl(
1048            name='upload_pdfscanmanageupload').click()
1049        self.assertTrue(
1050            'pdf file extension expected' in self.browser.contents)
1051        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1052        file_ctrl = ctrl.mech_control
1053        file_ctrl.add_file(image, filename='my_sample_scan.pdf')
1054        self.browser.getControl(
1055            name='upload_pdfscanmanageupload').click()
1056        self.assertTrue(
1057            'Could not determine file type' in self.browser.contents)
1058        pdf = open(SAMPLE_PDF, 'rb')
1059        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1060        file_ctrl = ctrl.mech_control
1061        file_ctrl.add_file(pdf, filename='my_sample_scan.pdf')
1062        self.browser.getControl(
1063            name='upload_pdfscanmanageupload').click()
1064        self.assertTrue(
1065            'href="http://localhost/app/customers/K1000000/documents/d102/sample.pdf">PDF File</a>'
1066            in self.browser.contents)
1067        # Browsing the link shows a real pdf
1068        self.browser.open('sample.pdf')
1069        self.assertEqual(
1070            self.browser.headers['content-type'], 'application/pdf')
1071
1072    def test_view_slips(self):
1073        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1074        # Officers can open the document overview
1075        self.browser.open(self.customer_path + '/documents')
1076        self.browser.getLink("Download documents overview").click()
1077        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1078        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1079        path = os.path.join(samples_dir(), 'documents_overview_slip.pdf')
1080        open(path, 'wb').write(self.browser.contents)
1081        print "Sample PDF overview_slip.pdf written to %s" % path
1082        # Officers can open document slips which shows a thumbnail of
1083        # the jpeg file attached.
1084        file_id = IFileStoreNameChooser(self.document).chooseName(attr='sample.jpg')
1085        fs = ExtFileStore(root=self.dc_root)
1086        jpegfile = open(SAMPLE_IMAGE, 'rb')
1087        fs.createFile(file_id, jpegfile)
1088        self.browser.open(self.customer_path + '/documents/d101')
1089        self.browser.getLink("Download document slip").click()
1090        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1091        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1092        path = os.path.join(samples_dir(), 'document_slip.pdf')
1093        open(path, 'wb').write(self.browser.contents)
1094        print "Sample document_slip.pdf written to %s" % path
1095        # Officers can open merged pdf document slips
1096        pdfdocument = createObject('waeup.CustomerPDFDocument')
1097        pdfdocument.title = u'My first document'
1098        self.customer['documents'].addDocument(pdfdocument)
1099        # Add pdf file
1100        file_id = IFileStoreNameChooser(pdfdocument).chooseName(attr='sample.pdf')
1101        fs = ExtFileStore(root=self.dc_root)
1102        pdffile = open(SAMPLE_PDF, 'rb')
1103        fs.createFile(file_id, pdffile)
1104        self.browser.open(self.customer_path + '/documents/d102')
1105        self.browser.getLink("Download document slip").click()
1106        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1107        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1108        path = os.path.join(samples_dir(), 'pdfdocument_slip.pdf')
1109        open(path, 'wb').write(self.browser.contents)
1110        print "Sample pdfdocument_slip.pdf written to %s" % path
1111
1112    def test_get_setmd5_file(self):
1113        # A proper file name chooser is registered for customer documents.
1114        # This is not a UI test. It's just a functional test.
1115        file_id = IFileStoreNameChooser(self.document).chooseName(attr='sample')
1116        fs = ExtFileStore(root=self.dc_root)
1117        fs.createFile(file_id, StringIO('my sample 1'))
1118        result = fs.getFileByContext(self.document, attr='sample')
1119        self.assertEqual(file_id, '__file-customerdocument__01000/K1000000/sample_d101_K1000000')
1120        self.assertEqual(result.read(), 'my sample 1')
1121        self.assertEqual(self.document.connected_files[0][1].read(), 'my sample 1')
1122        self.document.setMD5()
1123        self.assertEqual(self.document.sample_md5, 'a406995ee8eb6772bacf51aa4b0caa24')
1124        return
1125
1126
1127class ContractUITests(CustomersFullSetup):
1128    # Tests for CustomerSampleContract relates views and pages
1129
1130    def test_manage_contract(self):
1131        # Managers can access the pages of customer contractsconter
1132        # and can perform actions
1133        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1134        self.browser.open(self.customer_path)
1135        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1136        self.assertEqual(self.browser.url, self.customer_path)
1137        self.browser.open(self.customer_path)
1138        self.browser.getLink("Contracts").click()
1139        self.browser.getLink("Add contract").click()
1140        self.browser.getControl(name="contype").value = ['SampleContract']
1141        self.browser.getControl("Create contract").click()
1142        self.assertTrue('Sample Contract created.' in self.browser.contents)
1143        contract = self.customer['contracts']['c102']
1144
1145        # Contract can be edited
1146        self.browser.getLink("c102").click()
1147        self.browser.getLink("Manage").click()
1148        self.browser.getControl(name="form.product_object").value = ['SAM']
1149        self.browser.getControl(name="form.title").value = 'My second contract'
1150        self.browser.getControl("Save").click()
1151        self.assertTrue('Form has been saved.' in self.browser.contents)
1152        self.browser.getLink("View").click()
1153        self.assertEqual(self.browser.url, self.contracts_path + '/c102/index')
1154
1155        # Transitions can be performed
1156        self.browser.getLink("Transition").click()
1157        self.browser.getControl(name="transition").value = ['submit']
1158        self.browser.getControl("Save").click()
1159        self.browser.getControl(name="transition").value = ['approve']
1160        self.browser.getControl("Save").click()
1161        self.assertEqual(contract.state, 'approved')
1162
1163        # Contracts can be removed
1164        self.browser.getLink("Contracts").click()
1165        ctrl = self.browser.getControl(name='val_id')
1166        ctrl.getControl(value=contract.contract_id).selected = True
1167        self.browser.getControl("Remove selected", index=0).click()
1168        self.assertTrue('Successfully removed' in self.browser.contents)
1169
1170        # All actions are being logged
1171        logfile = os.path.join(
1172            self.app['datacenter'].storage, 'logs', 'customers.log')
1173        logcontent = open(logfile).read()
1174        self.assertTrue(
1175            'INFO - zope.mgr - customers.browser.ContractManageFormPage '
1176            '- K1000000 - c102 - saved: title'
1177            in logcontent)
1178        self.assertTrue(
1179            'INFO - zope.mgr - customers.browser.ContractAddFormPage '
1180            '- K1000000 - added: Sample Contract %s'
1181            % contract.contract_id in logcontent)
1182        self.assertTrue(
1183            'INFO - zope.mgr - customers.browser.ContractsManageFormPage '
1184            '- K1000000 - removed: %s'
1185            % contract.contract_id in logcontent)
1186
1187    def test_edit_sample_contract(self):
1188        # We add a second product.
1189        product = createObject('waeup.Product')
1190        product.product_id = u'LIC'
1191        product.title = u'Our License Product'
1192        product.contract_category = u'license'
1193        self.app['products'].addProduct(product)
1194        # Customers can manage contracts under certain conditions
1195        self.browser.open(self.login_path)
1196        self.browser.getControl(name="form.login").value = self.customer_id
1197        self.browser.getControl(name="form.password").value = 'cpwd'
1198        self.browser.getControl("Login").click()
1199        self.assertMatches(
1200            '...You logged in...', self.browser.contents)
1201        self.browser.getLink("Contracts").click()
1202        self.browser.getLink("Add contract").click()
1203        self.browser.getControl(name="contype").value = ['SampleContract']
1204        self.browser.getControl("Create contract").click()
1205        self.assertTrue('Sample Contract created.' in self.browser.contents)
1206        contract = self.customer['contracts']['c102']
1207        # Contract can be edited ...
1208        self.browser.open(self.contracts_path + '/c102/edit')
1209        #self.browser.getLink("Edit").click()
1210        self.assertTrue('The requested form is locked' in self.browser.contents)
1211        # Customer is in wrong state
1212        IWorkflowState(self.customer).setState(APPROVED)
1213        self.browser.open(self.contracts_path + '/c102/edit')
1214        self.browser.getControl(name="form.title").value = 'My second contract'
1215        # SAM is in the correct contract_category ...
1216        self.assertTrue('<option value="SAM">' in self.browser.contents)
1217        # ... but NOTSAM not.
1218        self.assertFalse('<option value="LIC">' in self.browser.contents)
1219        # So far last_product_id is None.
1220        self.assertTrue(self.customer['contracts']['c102'].last_product_id is None)
1221        self.browser.getControl(name="form.product_object").value = ['SAM']
1222        self.browser.getControl("Save").click()
1223        # Document is a required field on edit form page.
1224        self.assertTrue('Document: <span class="error">Required input is missing.</span>'
1225            in self.browser.contents)
1226        # But our document can't be selected because it's not submitted
1227        self.assertFalse('My first document' in self.browser.contents)
1228        IWorkflowState(self.document).setState(SUBMITTED)
1229        self.browser.open(self.contracts_path + '/c102/edit')
1230        self.browser.getControl(name="form.product_object").value = ['SAM']
1231        self.browser.getControl(name="form.document_object").value = ['d101']
1232        self.browser.getControl(name="form.title").value = 'My second contract'
1233        self.browser.getControl("Save").click()
1234        # After saving the form, last_product_id and other attributes are set
1235        self.assertTrue('Form has been saved.' in self.browser.contents)
1236        self.assertEqual(self.customer['contracts']['c102'].last_product_id, 'SAM')
1237        self.assertEqual(contract.title, 'My second contract')
1238        self.assertEqual(contract.product_object, self.product)
1239        self.assertEqual(contract.document_object, self.document)
1240        # Saving the form again does not unset last_product_id
1241        self.browser.getControl(name="form.title").value = 'My third contract'
1242        self.browser.getControl("Save").click()
1243        self.assertEqual(self.customer['contracts']['c102'].last_product_id, 'SAM')
1244        self.assertTrue('Form has been saved.' in self.browser.contents)
1245        self.browser.getLink("View").click()
1246        self.assertEqual(self.browser.url, self.contracts_path + '/c102/index')
1247        # An href attribute is referring to the document and product objects
1248        self.assertTrue('<a href="http://localhost/app/products/SAM">SAM -'
1249            in self.browser.contents)
1250        self.assertTrue(
1251            '<a href="http://localhost/app/customers/K1000000/documents/d101">d101 -'
1252            in self.browser.contents)
1253        # Customer can submit the form. The form is also saved.
1254        self.browser.getLink("Edit").click()
1255        self.browser.getControl(name="form.title").value = 'My fourth contract'
1256        self.browser.getControl("Apply now").click()
1257        self.assertEqual(contract.title, 'My fourth contract')
1258        self.assertEqual(contract.state, 'submitted')
1259        self.assertTrue('Contract State: submitted for approval' in self.browser.contents)
1260        # Customer can't edit the contract once it has been submitted
1261        self.browser.open(self.contracts_path + '/c102/edit')
1262        self.assertTrue('The requested form is locked' in self.browser.contents)
1263
1264    def test_view_slips(self):
1265        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1266        # Officers can open the contract overview
1267        self.browser.open(self.customer_path + '/contracts')
1268        self.browser.getLink("Download contracts overview").click()
1269        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1270        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1271        path = os.path.join(samples_dir(), 'contracts_overview_slip.pdf')
1272        open(path, 'wb').write(self.browser.contents)
1273        print "Sample PDF overview_slip.pdf written to %s" % path
1274        # Officers can open contract slips.
1275        # First we add a submitted document and a product.
1276        IWorkflowState(self.document).setState(SUBMITTED)
1277        self.contract.document_object = self.document
1278        self.contract.product_object = self.product
1279        self.browser.open(self.customer_path + '/contracts/c101')
1280        self.browser.getLink("Download contract slip").click()
1281        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1282        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1283        path = os.path.join(samples_dir(), 'contract_slip.pdf')
1284        open(path, 'wb').write(self.browser.contents)
1285        print "Sample contract_slip.pdf written to %s" % path
1286
1287    def test_contract_approval(self):
1288        # This is not a UI test. It just a functional test.
1289        self.assertRaises(ConstraintNotSatisfied,
1290            self.contract.document_object, self.document)
1291        # Document must be at least submitted
1292        IWorkflowState(self.document).setState('submitted')
1293        self.contract.document_object = self.document
1294        IWorkflowState(self.contract).setState('submitted')
1295        self.assertRaises(InvalidTransitionError,
1296            IWorkflowInfo(self.contract).fireTransition, 'approve')
1297        # Document must be verified for the approval of contracts
1298        IWorkflowState(self.document).setState('verified')
1299        IWorkflowInfo(self.contract).fireTransition('approve')
1300        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
1301
1302    def test_contract_approval_in_UI(self):
1303        # Now let's see what the UI says why trying to approve a contract
1304        # with unverified documents.
1305        IWorkflowState(self.document).setState('submitted')
1306        self.contract.document_object = self.document
1307        IWorkflowState(self.contract).setState('submitted')
1308        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1309        self.browser.open(self.contracts_path + '/c101/trigtrans')
1310        self.browser.getControl(name="transition").value = ['approve']
1311        self.browser.getControl("Save").click()
1312        # InvalidTransitionError is catched
1313        self.assertTrue(
1314            '<div class="alert alert-warning">Attached documents must be verified first.</div>'
1315            in self.browser.contents)
1316        IWorkflowState(self.document).setState('verified')
1317        self.browser.getControl(name="transition").value = ['approve']
1318        self.browser.getControl("Save").click()
1319        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
Note: See TracBrowser for help on using the repository browser.