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

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

Log workflow transitions properly.

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