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

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

Validate product id properly. Add tests.

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