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

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

Set md5 attributes when verifying a document.

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