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

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

Remove session configuration. We do not have sessions in Ikoba.

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