Changeset 12741 for main/waeup.ikoba/trunk/src/waeup/ikoba/customers
- Timestamp:
- 12 Mar 2015, 05:29:43 (10 years ago)
- Location:
- main/waeup.ikoba/trunk/src/waeup/ikoba/customers
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
r12663 r12741 18 18 """UI components for customers and related components. 19 19 """ 20 21 import sys22 20 import grok 23 import pytz24 21 import os 25 22 from urllib import urlencode 26 from datetime import datetime27 23 from zope.event import notify 28 24 from zope.i18n import translate 29 25 from zope.catalog.interfaces import ICatalog 30 26 from zope.component import queryUtility, getUtility, createObject 31 from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing32 from zope.formlib.textwidgets import BytesDisplayWidget33 27 from zope.security import checkPermission 34 28 from hurry.workflow.interfaces import ( … … 42 36 from waeup.ikoba.browser.layout import ( 43 37 IkobaPage, IkobaEditFormPage, IkobaAddFormPage, IkobaDisplayFormPage, 44 IkobaForm, NullValidator, jsaction, action, UtilityView) 45 from waeup.ikoba.widgets.datewidget import ( 46 FriendlyDateWidget, FriendlyDateDisplayWidget, 47 FriendlyDatetimeDisplayWidget) 38 NullValidator, jsaction, action, UtilityView) 48 39 from waeup.ikoba.browser.pages import ContactAdminForm 49 40 from waeup.ikoba.browser.breadcrumbs import Breadcrumb 50 41 from waeup.ikoba.browser.interfaces import ICaptchaManager 51 42 from waeup.ikoba.mandates.mandate import PasswordMandate 43 from waeup.ikoba.payments.payment import format_payment_item_values 44 from waeup.ikoba.payments.interfaces import ( 45 IPaymentGatewayServicesLister, IPaymentGatewayService, IPayer, IPayable 46 ) 52 47 from waeup.ikoba.widgets.hrefwidget import HREFDisplayWidget 53 48 from waeup.ikoba.utils.helpers import ( 54 get_current_principal, to_timezone, now,format_date)49 get_current_principal, format_date) 55 50 from waeup.ikoba.customers.interfaces import ( 56 51 ICustomer, ICustomersContainer, ICustomerRequestPW, ICustomersUtils, 57 52 ICustomerDocument, ICustomerDocumentsContainer, ICustomerCreate, 58 53 ICustomerPDFDocument, IContractsContainer, IContract, 59 IContractSelectProduct, ISampleContract,54 IContractSelectProduct, 60 55 ) 61 56 from waeup.ikoba.customers.catalog import search 62 57 from waeup.ikoba.customers.workflow import PAYMENT_TRANSITIONS 58 63 59 64 60 grok.context(IIkobaObject) … … 927 923 def createDocument(self, **data): 928 924 form = self.request.form 929 customer = self.context.__parent__930 925 doctype = form.get('doctype', None) 931 926 # Here we can create various instances of CustomerDocument derived … … 1098 1093 tableheader = [] 1099 1094 tabledata = [] 1100 contenttitle = []1101 1095 for i in range(1,3): 1102 1096 tabledata.append(sorted( … … 1134 1128 @property 1135 1129 def label(self): 1136 portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE1137 1130 return '%s of %s\nTitle: %s' % ( 1138 1131 self.context.translated_class_name, … … 1141 1134 1142 1135 def render(self): 1143 portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE1144 1136 customerview = CustomerBasePDFFormPage(self.context.customer, 1145 1137 self.request, self.omit_fields) … … 1157 1149 1158 1150 def render(self): 1159 portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE1160 1151 customerview = CustomerBasePDFFormPage(self.context.customer, 1161 1152 self.request, self.omit_fields) … … 1295 1286 def createContract(self, **data): 1296 1287 form = self.request.form 1297 customer = self.context.__parent__1298 1288 contype = form.get('contype', None) 1299 1289 # Here we can create various instances of Contract derived … … 1506 1496 label = _('Select payment method') 1507 1497 1508 def update(self, CANCEL=None): 1498 @property 1499 def payment_gateways(self): 1500 """Get an iter over registered and enabled gateway service providers. 1501 1502 We provide tuples ``(value, description)`` for each supported 1503 payment gateway. 1504 """ 1505 lister = getUtility(IPaymentGatewayServicesLister) 1506 for name, service in lister().items(): 1507 yield {'name': name, 'title': service.title} 1508 1509 def update(self, CANCEL=None, gw=None): 1509 1510 if self.context.state != CREATED or not self.context.fee_based: 1510 1511 emit_lock_message(self) 1511 1512 return 1513 self.gw = gw 1512 1514 super(SelectPaymentMethodPage, self).update() 1513 1515 return 1514 1516 1515 @action(_('Select payment method and proceed to payment gateway(final submission)'),1516 style='primary' , warning=WARNING_CON,)1517 @action(_('Select payment method (final submission)'), 1518 style='primary') 1517 1519 def confirm(self, **data): 1518 IWorkflowInfo(self.context).fireTransition('await') 1519 self.flash(_('Payment has been initiated.')) 1520 return 1520 if self.gw is None: 1521 self.flash(_('Please pick a payment method.'), 1522 type='warning') 1523 else: 1524 service = queryUtility(IPaymentGatewayService, name=self.gw) 1525 if service is None: 1526 self.flash(_('Invalid payment gateway.'), type='danger') 1527 return 1528 payer = IPayer(self.context) 1529 payable = IPayable(self.context) 1530 payment = service.create_payment(payer, payable) 1531 service.store(payment) 1532 payment, view_name = service.next_step(payment.payment_id) 1533 url = self.url(payment, view_name) 1534 self.redirect(url) 1535 return 1536 return 1537 1538 @action(_('Cancel')) 1539 def cancel(self, **data): 1540 self.redirect(self.url(self.context, 'edit')) 1541 return 1542 1521 1543 1522 1544 class ContractTriggerTransitionFormPage(IkobaEditFormPage): … … 1600 1622 tableheader = [] 1601 1623 tabledata = [] 1602 contenttitle = []1603 1624 for i in range(1,3): 1604 1625 tabledata.append(sorted( … … 1655 1676 @property 1656 1677 def label(self): 1657 portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE1658 1678 return self.context.title 1659 1679 … … 1670 1690 1671 1691 def render(self): 1672 portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE1673 1692 customerview = CustomerBasePDFFormPage(self.context.customer, 1674 1693 self.request, self.omit_fields) -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/selectpaymentmethodpage.pt
r12663 r12741 1 1 2 <form action="." tal:attributes="action request/URL" method="post" 2 3 i18n:domain="waeup.ikoba" enctype="multipart/form-data"> 3 4 4 <table class="form-table"> 5 <tbody> 6 <tr> 7 <td class="fieldname" i18n:translate=""></td> 8 <td> 9 </td> 10 </tr> 11 <tr> 12 <td class="fieldname" i18n:translate=""></td> 13 <td> 5 <div class="form-group"> 14 6 15 </td> 16 </tr> 17 </tbody> 18 </table> 7 <div class="radio" tal:repeat="service view/payment_gateways"> 8 <label> 9 <input type="radio" name="gw" tal:attributes="value service/name" /> 10 <b><span tal:replace="service/title" /></b> 11 </label> 12 </div> 13 14 </div> 15 19 16 <br /> 20 17 -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/contracts.py
r12663 r12741 19 19 Customer contract components. 20 20 """ 21 import os22 21 import grok 23 from zope.component import queryUtility, getUtility 22 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState 23 from zope.catalog.interfaces import ICatalog 24 from zope.component import getUtility, queryUtility 24 25 from zope.component.interfaces import IFactory 25 26 from zope.interface import implementedBy 26 27 from zope.schema import getFields 27 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState28 28 from waeup.ikoba.interfaces import MessageFactory as _ 29 29 from waeup.ikoba.interfaces import ( 30 IIkobaUtils, IObjectHistory, 31 VERIFIED, APPROVED, PROVISIONALLY, 32 IIDSource) 30 IObjectHistory, VERIFIED, APPROVED, PROVISIONALLY, IIDSource) 33 31 from waeup.ikoba.customers.interfaces import ( 34 IContractsContainer, ICustomerNavigation, 35 IContract, IContractSelectProduct, ICustomersUtils, 36 ISampleContract, ISampleContractProcess, ISampleContractEdit, 37 ISampleContractOfficialUse) 38 from waeup.ikoba.customers.utils import generate_contract_id 32 IContractsContainer, ICustomerNavigation, IContract, 33 IContractSelectProduct, ICustomersUtils, ISampleContract, 34 ISampleContractProcess, ISampleContractEdit, ISampleContractOfficialUse) 35 from waeup.ikoba.payments.interfaces import ( 36 IPayer, IPayableFinder, IPayable, IPaymentWaitingForGatewayEvent, 37 STATE_PAID, STATE_FAILED, IPaymentFinishedEvent 38 ) 39 from waeup.ikoba.payments.payment import ( 40 PaymentItem, find_payable_from_payable_id, 41 ) 39 42 from waeup.ikoba.utils.helpers import attrs_to_fields 43 40 44 41 45 class ContractsContainer(grok.Container): … … 61 65 ContractsContainer = attrs_to_fields(ContractsContainer) 62 66 67 68 class ContractPayer(grok.Adapter): 69 """Adapter to turn contracts into IPayers. 70 """ 71 grok.implements(IPayer) 72 grok.context(IContract) 73 74 def __init__(self, context): 75 self.context = context 76 77 @property 78 def _customer(self): 79 return self.context.customer 80 81 @property 82 def first_name(self): 83 return getattr(self._customer, 'firstname', None) 84 85 @property 86 def last_name(self): 87 return getattr(self._customer, 'lastname', None) 88 89 @property 90 def payer_id(self): 91 return getattr(self._customer, 'customer_id', None) 92 93 63 94 class ContractBase(grok.Container): 64 95 """This is a customer contract baseclass. 65 96 """ 66 grok.implements(IContractSelectProduct) # Nec esary for the selectproduct page67 97 grok.implements(IContractSelectProduct) # Neccessary for the 98 # selectproduct page (why?) 68 99 grok.baseclass() 69 100 … … 150 181 state = getattr(obj, 'state', None) 151 182 if state and state != VERIFIED: 152 return False, _("Attached documents must be verified first.") 183 return False, _( 184 "Attached documents must be verified first.") 153 185 return True, None 154 186 … … 177 209 178 210 grok.implements( 179 ISampleContractProcess, # must come before ISampleContract211 ISampleContractProcess, # must come before ISampleContract 180 212 ISampleContract, 181 213 ISampleContractEdit, … … 210 242 return implementedBy(SampleContract) 211 243 244 212 245 @grok.subscribe(IContract, grok.IObjectAddedEvent) 213 246 def handle_contract_added(contract, event): … … 218 251 IWorkflowInfo(contract).fireTransition('create') 219 252 return 253 254 255 @grok.subscribe(IPaymentWaitingForGatewayEvent) 256 def handle_payment_waiting_for_gw(event): 257 maybe_contract = find_payable_from_payable_id( 258 event.object.payable_id) 259 if IContract.providedBy(maybe_contract): 260 IWorkflowInfo(maybe_contract).fireTransition('await') 261 262 263 @grok.subscribe(IPaymentFinishedEvent) 264 def handle_payment_finished(event): 265 payment = event.object 266 maybe_contract = find_payable_from_payable_id(payment.payable_id) 267 if not IContract.providedBy(maybe_contract): 268 return 269 if payment.state == STATE_PAID: 270 IWorkflowInfo(maybe_contract).fireTransition('confirm') 271 else: 272 IWorkflowInfo(maybe_contract).fireTransition('discard') 273 274 275 class ContractFinder(grok.GlobalUtility): 276 grok.name('contracts_finder') 277 grok.implements(IPayableFinder) 278 279 def get_payable_by_id(self, contract_id): 280 catalog = queryUtility(ICatalog, 'contracts_catalog') 281 if catalog is None: 282 return None 283 result = catalog.searchResults( 284 contract_id=(contract_id, contract_id)) 285 result = [x for x in result] 286 if not result: 287 return None 288 # there should not be more than one result really. 289 return result[0] 290 291 292 class PayableContract(grok.Adapter): 293 """Adapter to adapt IContracts to IPayable. 294 """ 295 296 grok.context(IContract) 297 grok.implements(IPayable) 298 299 def __init__(self, context): 300 self.context = context 301 currencies = set([x.currency for x in context.product_options]) 302 if len(currencies) > 1: 303 raise ValueError( 304 "Only contracts with same currency for all options allowed.") 305 return 306 307 @property 308 def payable_id(self): 309 return self.context.contract_id 310 311 @property 312 def title(self): 313 return self.context.title or u'' 314 315 @property 316 def currency(self): 317 if not len(self.context.product_options): 318 return None 319 return self.context.product_options[0].currency 320 321 @property 322 def payment_items(self): 323 result = [] 324 for num, option in enumerate(self.context.product_options): 325 item = PaymentItem() 326 item.item_id = u'%s' % num 327 item.title = option.title 328 item.amount = option.fee 329 result.append(item) 330 return tuple(result) -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/customer.py
r12553 r12741 25 25 from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo 26 26 from zope.password.interfaces import IPasswordManager 27 from zope.component import getUtility, createObject 27 from zope.catalog.interfaces import ICatalog 28 from zope.component import getUtility, queryUtility 28 29 from zope.component.interfaces import IFactory 29 30 from zope.interface import implementedBy 30 31 from zope.securitypolicy.interfaces import IPrincipalRoleManager 31 from zope.schema.interfaces import ConstraintNotSatisfied32 32 33 33 from waeup.ikoba.image import IkobaImageFile … … 35 35 from waeup.ikoba.interfaces import ( 36 36 IObjectHistory, IUserAccount, IFileStoreNameChooser, IFileStoreHandler, 37 IIkobaUtils, IExtFileStore, 38 CREATED, REQUESTED, APPROVED) 37 IIkobaUtils, IExtFileStore, ) 39 38 from waeup.ikoba.customers.interfaces import ( 40 39 ICustomer, ICustomerNavigation, ICSVCustomerExporter, … … 43 42 from waeup.ikoba.customers.documents import CustomerDocumentsContainer 44 43 from waeup.ikoba.customers.contracts import ContractsContainer 45 from waeup.ikoba.utils.helpers import attrs_to_fields, now, copy_filesystem_tree 44 from waeup.ikoba.payments.interfaces import IPayer, IPayerFinder 45 from waeup.ikoba.utils.helpers import ( 46 attrs_to_fields, now, copy_filesystem_tree) 47 46 48 47 49 class Customer(grok.Container): … … 77 79 'password'] = passwordmanager.encodePassword(password) 78 80 self.temp_password['user'] = user 79 self.temp_password['timestamp'] = datetime.utcnow() # offset-naive datetime 81 self.temp_password[ 82 'timestamp'] = datetime.utcnow() # offset-naive datetime 80 83 81 84 def getTempPassword(self): … … 89 92 if temp_password_dict is not None: 90 93 delta = timedelta(minutes=self.temp_password_minutes) 91 now = datetime.utcnow()92 if now < temp_password_dict.get('timestamp') + delta:94 dt_now = datetime.utcnow() 95 if dt_now < temp_password_dict.get('timestamp') + delta: 93 96 return temp_password_dict.get('password') 94 97 else: … … 98 101 99 102 def writeLogMessage(self, view, message): 100 ob_class = view.__implemented__.__name__.replace('waeup.ikoba.','') 103 ob_class = view.__implemented__.__name__.replace( 104 'waeup.ikoba.', '') 101 105 self.__parent__.logger.info( 102 106 '%s - %s - %s' % (ob_class, self.__name__, message)) … … 196 200 return 197 201 202 198 203 def move_customer_files(customer, del_dir): 199 204 """Move files belonging to `customer` to `del_dir`. … … 246 251 timestamp = str(now().replace(microsecond=0)) # store UTC timestamp 247 252 for num, row in enumerate(csv_data[1:-1]): 248 csv_data[num +1] = csv_data[num+1] + ',' + timestamp253 csv_data[num + 1] = csv_data[num + 1] + ',' + timestamp 249 254 csv_path = os.path.join(del_dir, '%s.csv' % name) 250 255 … … 399 404 return file, path, IkobaImageFile( 400 405 file_obj.filename, file_obj.data) 406 407 408 class CustomerPayer(grok.Adapter): 409 """Adapter to turn customers into IPayers. 410 """ 411 grok.implements(IPayer) 412 grok.context(ICustomer) 413 414 @property 415 def first_name(self): 416 return getattr(self.context, 'firstname', None) 417 418 @property 419 def last_name(self): 420 return getattr(self.context, 'lastname', None) 421 422 @property 423 def payer_id(self): 424 return getattr(self.context, 'customer_id', None) 425 426 427 class CustomerFinder(grok.GlobalUtility): 428 """Find customers. 429 """ 430 grok.name('customer_finder') 431 grok.implements(IPayerFinder) 432 433 def get_payer_by_id(self, customer_id): 434 catalog = queryUtility(ICatalog, 'customers_catalog') 435 if catalog is None: 436 return None 437 result = catalog.searchResults( 438 customer_id=(customer_id, customer_id)) 439 result = [x for x in result] 440 if not result: 441 return None 442 # there should not be more than one result really. 443 return result[0] -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/export.py
r12500 r12741 215 215 'translated_class_name', 216 216 'is_editable', 217 'is_approvable']))) 217 'is_approvable', 218 'customer']))) 218 219 219 220 def filter_func(self, x, **kw): -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py
r12663 r12741 298 298 is_approvable = Attribute('Contract approvable by officer') 299 299 translated_class_name = Attribute('Translatable class name') 300 customer = Attribute('Customer object of context.') 300 301 user_id = Attribute('Id of a user, actually the id of the customer') 301 302 title = Attribute('Title generated by the associated product') -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py
r12663 r12741 1 1 ## $Id$ 2 ## 2 ## 3 3 ## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann 4 4 ## This program is free software; you can redistribute it and/or modify … … 6 6 ## the Free Software Foundation; either version 2 of the License, or 7 7 ## (at your option) any later version. 8 ## 8 ## 9 9 ## This program is distributed in the hope that it will be useful, 10 10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 11 11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 12 ## GNU General Public License for more details. 13 ## 13 ## 14 14 ## You should have received a copy of the GNU General Public License 15 15 ## along with this program; if not, write to the Free Software … … 22 22 import tempfile 23 23 import logging 24 import pytz25 24 import base64 26 25 from decimal import Decimal … … 42 41 from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase 43 42 from waeup.ikoba.app import Company 44 from waeup.ikoba.customers.interfaces import ICustomersUtils45 from waeup.ikoba.customers.customer import Customer46 43 from waeup.ikoba.interfaces import ( 47 44 IUserAccount, IJobManager, APPROVED, SUBMITTED, 48 IFileStoreNameChooser, IExtFileStore, IFileStoreHandler, NotIdValue) 49 from waeup.ikoba.imagestorage import ( 50 FileStoreNameChooser, ExtFileStore, DefaultFileStoreHandler, 51 DefaultStorage) 52 from waeup.ikoba.authentication import LocalRoleSetEvent 45 IFileStoreNameChooser, NotIdValue) 46 from waeup.ikoba.imagestorage import ExtFileStore 53 47 from waeup.ikoba.tests.test_async import FunctionalAsyncTestCase 54 48 from waeup.ikoba.interfaces import VERIFIED … … 61 55 SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp') 62 56 SAMPLE_PDF = os.path.join(os.path.dirname(__file__), 'test_pdf.pdf') 57 63 58 64 59 def lookup_submit_value(name, value, browser): … … 72 67 break 73 68 return None 69 74 70 75 71 class CustomersFullSetup(FunctionalTestCase): … … 119 115 prodoption.fee = Decimal('99.9') 120 116 prodoption.currency = 'USD' 121 self.product.options = [prodoption, ]117 self.product.options = [prodoption, ] 122 118 self.app['products'].addProduct(self.product) 123 119 … … 138 134 self.document.document_id = u'DOC1' 139 135 self.assertRaises( 140 NotIdValue, setattr, self.document, 'document_id', u'id with spaces') 136 NotIdValue, setattr, self.document, 'document_id', 137 u'id with spaces') 141 138 self.customer['documents'].addDocument(self.document) 142 139 self.contract = createObject(self._contract_factory) 143 140 self.contract.contract_id = u'CON1' 144 141 self.assertRaises( 145 NotIdValue, setattr, self.contract, 'contract_id', u'id with spaces') 142 NotIdValue, setattr, self.contract, 'contract_id', 143 u'id with spaces') 146 144 self.customer['contracts'].addContract(self.contract) 147 145 … … 299 297 return 300 298 299 301 300 class OfficerUITests(CustomersFullSetup): 302 301 # Tests for Customer class views and pages 303 304 302 305 303 def setup_logging(self): … … 331 329 self.browser.getLink("Logout").click() 332 330 self.assertTrue('You have been logged out' in self.browser.contents) 333 # But we are still logged in since we've used basic authentication here. 334 # Wikipedia says: Existing browsers retain authentication information 335 # until the tab or browser is closed or the user clears the history. 336 # HTTP does not provide a method for a server to direct clients to 337 # discard these cached credentials. This means that there is no 338 # effective way for a server to "log out" the user without closing 339 # the browser. This is a significant defect that requires browser 340 # manufacturers to support a "logout" user interface element ... 331 # But we are still logged in since we've used basic 332 # authentication here. Wikipedia says: Existing browsers 333 # retain authentication information until the tab or browser 334 # is closed or the user clears the history. HTTP does not 335 # provide a method for a server to direct clients to discard 336 # these cached credentials. This means that there is no 337 # effective way for a server to "log out" the user without 338 # closing the browser. This is a significant defect that 339 # requires browser manufacturers to support a "logout" user 340 # interface element ... 341 341 self.assertTrue('Manager' in self.browser.contents) 342 342 … … 378 378 self.browser.open(self.customer_path) 379 379 self.browser.getLink("Send email").click() 380 self.browser.getControl(name="form.subject").value = 'Important subject' 380 self.browser.getControl( 381 name="form.subject").value = 'Important subject' 381 382 self.browser.getControl(name="form.body").value = 'Hello!' 382 383 self.browser.getControl("Send message now").click() … … 410 411 self.assertTrue('passport.jpg deleted' in self.browser.contents) 411 412 412 413 413 def test_manage_workflow_send_transition_information(self): 414 414 # Managers can pass through the whole workflow … … 417 417 self.setup_logging() 418 418 self.browser.addHeader('Authorization', 'Basic mgr:mgrpw') 419 customer = self.app['customers'][self.customer_id]419 self.customer = self.app['customers'][self.customer_id] 420 420 self.browser.open(self.trigtrans_path) 421 421 self.browser.getControl(name="transition").value = ['start'] … … 459 459 self.browser.getControl("Apply").click() 460 460 self.browser.open(self.trigtrans_path) 461 self.browser.getControl(name="transition").value = ['approve_provisionally'] 461 self.browser.getControl(name="transition").value = [ 462 'approve_provisionally'] 462 463 self.browser.getControl("Apply").click() 463 464 self.browser.open(self.trigtrans_path) … … 499 500 self.browser.getControl('Perform import').click() 500 501 self.assertTrue('Processing of 1 rows failed' in self.browser.contents) 501 self.assertTrue('Successfully processed 2 rows' in self.browser.contents) 502 self.assertTrue( 503 'Successfully processed 2 rows' in self.browser.contents) 502 504 self.assertTrue('Batch processing finished' in self.browser.contents) 503 505 … … 535 537 self.browser.getLink("History").click() 536 538 self.assertTrue( 537 'Customer account deactivated by Manager<br />' in self.browser.contents) 538 self.assertTrue( 539 'Customer account activated by Manager<br />' in self.browser.contents) 539 'Customer account deactivated by Manager<br />' 540 in self.browser.contents) 541 self.assertTrue( 542 'Customer account activated by Manager<br />' 543 in self.browser.contents) 540 544 # ... and actions have been logged. 541 545 logfile = os.path.join( 542 546 self.app['datacenter'].storage, 'logs', 'customers.log') 543 547 logcontent = open(logfile).read() 544 self.assertTrue('zope.mgr - customers.browser.CustomerDeactivatePage - ' 545 'K1000000 - account deactivated' in logcontent) 546 self.assertTrue('zope.mgr - customers.browser.CustomerActivatePage - ' 547 'K1000000 - account activated' in logcontent) 548 548 self.assertTrue( 549 'zope.mgr - customers.browser.CustomerDeactivatePage - ' 550 'K1000000 - account deactivated' in logcontent) 551 self.assertTrue( 552 'zope.mgr - customers.browser.CustomerActivatePage - ' 553 'K1000000 - account activated' in logcontent) 549 554 550 555 def test_login_as_customer(self): … … 554 559 self.app['users']['mrofficer'].title = 'Harry Actor' 555 560 prmglobal = IPrincipalRoleManager(self.app) 556 prmglobal.assignRoleToPrincipal('waeup.CustomerImpersonator', 'mrofficer') 561 prmglobal.assignRoleToPrincipal( 562 'waeup.CustomerImpersonator', 'mrofficer') 557 563 prmglobal.assignRoleToPrincipal('waeup.CustomersManager', 'mrofficer') 558 564 self.assertEqual(self.customer.state, 'created') … … 574 580 # We are logged in as customer and can see the 'My Data' tab 575 581 self.assertMatches( 576 '...<a href="#" class="dropdown-toggle" data-toggle="dropdown">...', 582 '...<a href="#" class="dropdown-toggle"' 583 ' data-toggle="dropdown">...', 577 584 self.browser.contents) 578 585 self.assertMatches( … … 724 731 self.assertMatches( 725 732 '...<div class="alert alert-warning">' 726 'Your account has been deactivated.</div>...', self.browser.contents) 733 'Your account has been deactivated.</div>...', 734 self.browser.contents) 727 735 # If suspended_comment is set this message will be flashed instead 728 736 self.customer.suspended_comment = u'Aetsch baetsch!' … … 778 786 self.assertTrue('An email with' in self.browser.contents) 779 787 788 780 789 class CustomerRegistrationTests(CustomersFullSetup): 781 790 # Tests for customer registration … … 823 832 cat.searchResults( 824 833 email=('new@yy.zz', 'new@yy.zz'))) 825 self.assertEqual(self.customer, results[0])834 self.assertEqual(self.customer, results[0]) 826 835 logfile = os.path.join( 827 836 self.app['datacenter'].storage, 'logs', 'main.log') 828 837 logcontent = open(logfile).read() 829 self.assertTrue('zope.anybody - customers.browser.CustomerRequestPasswordPage - ' 830 '123 (K1000000) - new@yy.zz' in logcontent) 838 self.assertTrue( 839 'zope.anybody - customers.browser.CustomerRequestPasswordPage - ' 840 '123 (K1000000) - new@yy.zz' in logcontent) 831 841 return 832 842 … … 841 851 self.browser.getControl(name="form.email").value = 'newcustomer@xx.zz' 842 852 self.browser.getControl("Send login credentials").click() 843 self.assertTrue('Your request was successful.' in self.browser.contents) 853 self.assertTrue( 854 'Your request was successful.' in self.browser.contents) 844 855 # Customer can be found in the catalog via the email address 845 856 cat = queryUtility(ICatalog, name='customers_catalog') … … 849 860 self.assertEqual(self.app['customers']['K1000001'], results[0]) 850 861 self.assertEqual(self.app['customers']['K1000001'].firstname, 'Ruben') 851 self.assertEqual(self.app['customers']['K1000001'].lastname, 'Gonzales') 862 self.assertEqual( 863 self.app['customers']['K1000001'].lastname, 'Gonzales') 852 864 logfile = os.path.join( 853 865 self.app['datacenter'].storage, 'logs', 'main.log') 854 866 logcontent = open(logfile).read() 855 self.assertTrue('zope.anybody - customers.browser.CustomerCreateAccountPage - ' 856 'K1000001 - newcustomer@xx.zz' in logcontent) 867 self.assertTrue( 868 'zope.anybody - customers.browser.CustomerCreateAccountPage - ' 869 'K1000001 - newcustomer@xx.zz' in logcontent) 857 870 return 871 858 872 859 873 class CustomerDataExportTests(CustomersFullSetup, FunctionalAsyncTestCase): … … 929 943 self.browser.getControl("Add document").click() 930 944 self.assertTrue('PDF Document added.' in self.browser.contents) 931 docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0] 945 docid = [i for i in self.customer['documents'].keys() 946 if len(i) > 10][0] 932 947 document = self.customer['documents'][docid] 933 948 … … 950 965 self.browser.getControl(name="transition").value = ['verify'] 951 966 self.browser.getControl("Apply").click() 952 self.assertTrue('Customer has not yet been approved' in self.browser.contents) 967 self.assertTrue( 968 'Customer has not yet been approved' in self.browser.contents) 953 969 IWorkflowState(self.customer).setState(APPROVED) 954 970 # Document can only be verified if files have been uploaded before … … 958 974 self.assertTrue('No file uploaded' in self.browser.contents) 959 975 self.assertEqual(document.state, 'submitted') 960 # We set state here manually (verification is tested in test_verify_document) 976 # We set state here manually (verification is tested in 977 # test_verify_document) 961 978 IWorkflowState(document).setState(VERIFIED) 962 979 … … 964 981 self.browser.open(self.documents_path + '/' + docid + '/index') 965 982 self.assertFalse( 966 'href="http://localhost/app/customers/K1000000/documents/%s/manage"' 983 'href="http://localhost/app/customers/K1000000/' 984 'documents/%s/manage"' 967 985 % docid in self.browser.contents) 968 986 self.browser.open(self.documents_path + '/' + docid + '/manage') … … 1012 1030 self.browser.getLink("Documents").click() 1013 1031 self.browser.getControl("Add document").click() 1014 self.assertTrue('The requested form is locked' in self.browser.contents) 1032 self.assertTrue( 1033 'The requested form is locked' in self.browser.contents) 1015 1034 # Customer is in wrong state 1016 1035 IWorkflowState(self.customer).setState(APPROVED) 1017 1036 self.browser.getControl("Add document").click() 1018 self.browser.getControl(name="doctype").value = ['CustomerSampleDocument'] 1037 self.browser.getControl(name="doctype").value = [ 1038 'CustomerSampleDocument'] 1019 1039 self.browser.getControl(name="form.title").value = 'My Sample Document' 1020 1040 self.browser.getControl("Add document").click() 1021 1041 self.assertTrue('Sample Document added.' in self.browser.contents) 1022 docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0] 1042 docid = [i for i in self.customer['documents'].keys() 1043 if len(i) > 10][0] 1023 1044 document = self.customer['documents'][docid] 1024 1045 self.browser.getControl(name="form.title").value = 'My second doc' … … 1038 1059 name='upload_samplescaneditupload').click() 1039 1060 self.assertTrue( 1040 'href="http://localhost/app/customers/K1000000/documents/%s/sample"' 1061 'href="http://localhost/app/customers/K1000000/' 1062 'documents/%s/sample"' 1041 1063 % docid in self.browser.contents) 1042 1064 # Customer can submit the form. The form is also saved. … … 1045 1067 self.assertEqual(document.title, 'My third doc') 1046 1068 self.assertEqual(document.state, 'submitted') 1047 self.assertTrue('Document State: submitted for verification' in self.browser.contents) 1069 self.assertTrue( 1070 'Document State: submitted for verification' 1071 in self.browser.contents) 1048 1072 # Customer can't edit the document once it has been submitted 1049 1073 self.browser.open(self.documents_path + '/%s/edit' % docid) 1050 self.assertTrue('The requested form is locked' in self.browser.contents) 1074 self.assertTrue( 1075 'The requested form is locked' in self.browser.contents) 1051 1076 1052 1077 def test_manage_upload_sample_file(self): … … 1055 1080 self.browser.addHeader('Authorization', 'Basic mgr:mgrpw') 1056 1081 self.browser.open(self.customer_path + '/documents/DOC1/manage') 1057 # Create a pseudo image file and select it to be uploaded 1082 # Create a pseudo image file and select it to be uploaded 1058 1083 image = open(SAMPLE_IMAGE, 'rb') 1059 1084 ctrl = self.browser.getControl(name='samplescanmanageupload') … … 1061 1086 file_ctrl.add_file(image, filename='my_sample_scan.jpg') 1062 1087 # The Save action does not upload files 1063 self.browser.getControl("Save").click() # submit form1088 self.browser.getControl("Save").click() # submit form 1064 1089 self.assertFalse( 1065 'href="http://localhost/app/customers/K1000000/documents/DOC1/sample"' 1090 'href="http://localhost/app/customers/K1000000/' 1091 'documents/DOC1/sample"' 1066 1092 in self.browser.contents) 1067 1093 # ... but the correct upload submit button does … … 1073 1099 name='upload_samplescanmanageupload').click() 1074 1100 self.assertTrue( 1075 'href="http://localhost/app/customers/K1000000/documents/DOC1/sample"' 1101 'href="http://localhost/app/customers/K1000000/' 1102 'documents/DOC1/sample"' 1076 1103 in self.browser.contents) 1077 1104 # Browsing the link shows a real image … … 1098 1125 'Uploaded file is too big' in self.browser.contents) 1099 1126 # We do not rely on filename extensions given by uploaders 1100 image = open(SAMPLE_IMAGE, 'rb') # a jpg-file1127 image = open(SAMPLE_IMAGE, 'rb') # a jpg-file 1101 1128 ctrl = self.browser.getControl(name='samplescanmanageupload') 1102 1129 file_ctrl = ctrl.mech_control … … 1152 1179 self.browser.getControl(name="form.title").value = 'My PDF Document' 1153 1180 self.browser.getControl("Add document").click() 1154 docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0] 1181 docid = [ 1182 i for i in self.customer['documents'].keys() if len(i) > 10][0] 1155 1183 self.browser.open(self.documents_path + '/%s/manage' % docid) 1156 1184 # Create a pseudo image file and select it to be uploaded … … 1177 1205 name='upload_pdfscanmanageupload').click() 1178 1206 self.assertTrue( 1179 'href="http://localhost/app/customers/K1000000/documents/%s/sample.pdf">%s.pdf</a>' 1207 'href="http://localhost/app/customers/K1000000/' 1208 'documents/%s/sample.pdf">%s.pdf</a>' 1180 1209 % (docid, docid[:9]) in self.browser.contents) 1181 1210 # Browsing the link shows a real pdf … … 1194 1223 self.browser.getLink("Download documents overview").click() 1195 1224 self.assertEqual(self.browser.headers['Status'], '200 Ok') 1196 self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf') 1225 self.assertEqual( 1226 self.browser.headers['Content-Type'], 'application/pdf') 1197 1227 path = os.path.join(samples_dir(), 'documents_overview_slip.pdf') 1198 1228 open(path, 'wb').write(self.browser.contents) … … 1200 1230 # Officers can open document slips which shows a thumbnail of 1201 1231 # the jpeg file attached. 1202 file_id = IFileStoreNameChooser(self.document).chooseName(attr='sample.jpg') 1232 file_id = IFileStoreNameChooser(self.document).chooseName( 1233 attr='sample.jpg') 1203 1234 fs = ExtFileStore(root=self.dc_root) 1204 1235 jpegfile = open(SAMPLE_IMAGE, 'rb') … … 1207 1238 self.browser.getLink("Download document slip").click() 1208 1239 self.assertEqual(self.browser.headers['Status'], '200 Ok') 1209 self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf') 1240 self.assertEqual( 1241 self.browser.headers['Content-Type'], 'application/pdf') 1210 1242 path = os.path.join(samples_dir(), 'document_slip.pdf') 1211 1243 open(path, 'wb').write(self.browser.contents) … … 1216 1248 self.customer['documents'].addDocument(pdfdocument) 1217 1249 # Add pdf file 1218 file_id = IFileStoreNameChooser(pdfdocument).chooseName(attr='sample.pdf') 1250 file_id = IFileStoreNameChooser(pdfdocument).chooseName( 1251 attr='sample.pdf') 1219 1252 fs = ExtFileStore(root=self.dc_root) 1220 1253 pdffile = open(SAMPLE_PDF, 'rb') 1221 1254 fs.createFile(file_id, pdffile) 1222 docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0] 1255 docid = [i for i in self.customer['documents'].keys() 1256 if len(i) > 10][0] 1223 1257 self.browser.open(self.customer_path + '/documents/' + docid) 1224 1258 self.browser.getLink("Download document slip").click() 1225 1259 self.assertEqual(self.browser.headers['Status'], '200 Ok') 1226 self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf') 1260 self.assertEqual( 1261 self.browser.headers['Content-Type'], 'application/pdf') 1227 1262 path = os.path.join(samples_dir(), 'pdfdocument_slip.pdf') 1228 1263 open(path, 'wb').write(self.browser.contents) … … 1232 1267 # A proper file name chooser is registered for customer documents. 1233 1268 # This is not a UI test. It's just a functional test. 1234 file_id = IFileStoreNameChooser(self.document).chooseName(attr='sample') 1269 file_id = IFileStoreNameChooser(self.document).chooseName( 1270 attr='sample') 1235 1271 fs = ExtFileStore(root=self.dc_root) 1236 1272 fs.createFile(file_id, StringIO('my sample 1')) 1237 1273 result = fs.getFileByContext(self.document, attr='sample') 1238 self.assertEqual(file_id, '__file-customerdocument__01000/K1000000/sample_DOC1_K1000000') 1274 self.assertEqual( 1275 file_id, '__file-customerdocument__01000/' 1276 'K1000000/sample_DOC1_K1000000') 1239 1277 self.assertEqual(result.read(), 'my sample 1') 1240 self.assertEqual(self.document.connected_files[0][1].read(), 'my sample 1') 1278 self.assertEqual( 1279 self.document.connected_files[0][1].read(), 'my sample 1') 1241 1280 self.document.setMD5() 1242 self.assertEqual(self.document.sample_md5, 'a406995ee8eb6772bacf51aa4b0caa24') 1281 self.assertEqual( 1282 self.document.sample_md5, 'a406995ee8eb6772bacf51aa4b0caa24') 1243 1283 return 1244 1284 … … 1246 1286 class ContractUITests(CustomersFullSetup): 1247 1287 # Tests for contract related views and pages 1288 1289 never_ending_button_text = ( 1290 'Select payment method (final submission)') 1291 1292 def add_product_option(self, contract): 1293 prodoption = ProductOption() 1294 prodoption.title = u'Any product option' 1295 prodoption.fee = Decimal('88.8') 1296 prodoption.currency = 'EUR' 1297 contract.product_options = [prodoption, ] 1298 1299 def prepare_payment_select(self): 1300 IWorkflowState(self.customer).setState('approved') 1301 IWorkflowState(self.document).setState('verified') 1302 self.contract.document_object = self.document 1303 self.add_product_option(self.contract) 1304 IWorkflowState(self.contract).setState('created') 1305 # login as customer 1306 self.browser.open(self.login_path) 1307 self.browser.getControl(name="form.login").value = self.customer_id 1308 self.browser.getControl(name="form.password").value = 'cpwd' 1309 self.browser.getControl("Login").click() 1248 1310 1249 1311 def test_manage_contract(self): … … 1261 1323 self.browser.getControl("Add contract").click() 1262 1324 self.assertTrue('Sample Contract added.' in self.browser.contents) 1263 conid = [i for i in self.customer['contracts'].keys() if len(i) > 10][0] 1325 conid = [i for i in self.customer['contracts'].keys() 1326 if len(i) > 10][0] 1264 1327 contract = self.customer['contracts'][conid] 1265 1328 self.assertEqual( 1266 self.browser.url, self.contracts_path + '/%s/selectproduct' % conid) 1329 self.browser.url, 1330 self.contracts_path + '/%s/selectproduct' % conid) 1267 1331 # SAM is in the correct contract_category 1268 1332 self.assertTrue('<option value="SAM">' in self.browser.contents) 1269 1333 # So far last_product_id is None. 1270 self.assertTrue(self.customer['contracts'][conid].last_product_id is None) 1334 self.assertTrue( 1335 self.customer['contracts'][conid].last_product_id is None) 1271 1336 self.browser.getControl(name="form.product_object").value = ['SAM'] 1272 1337 self.browser.getControl("Save and proceed").click() … … 1274 1339 self.browser.url, self.contracts_path + '/%s/manage' % conid) 1275 1340 self.browser.getLink("View").click() 1276 self.assertEqual(self.browser.url, self.contracts_path + '/%s/index' % conid) 1341 self.assertEqual( 1342 self.browser.url, self.contracts_path + '/%s/index' % conid) 1277 1343 self.assertEqual(contract.tc_dict, {'en': u'Hello world'}) 1278 1344 … … 1342 1408 self.assertFalse('Add contract' in self.browser.contents) 1343 1409 self.browser.open(self.contracts_path + '/addcontract') 1344 self.assertTrue('The requested form is locked' in self.browser.contents) 1410 self.assertTrue( 1411 'The requested form is locked' in self.browser.contents) 1345 1412 IWorkflowState(self.customer).setState(APPROVED) 1346 1413 self.browser.open(self.contracts_path) … … 1350 1417 self.browser.getControl("Add contract").click() 1351 1418 self.assertTrue('Sample Contract added.' in self.browser.contents) 1352 conid = [i for i in self.customer['contracts'].keys() if len(i) > 10][0] 1419 conid = [i for i in self.customer['contracts'].keys() 1420 if len(i) > 10][0] 1353 1421 contract = self.customer['contracts'][conid] 1354 1422 self.assertEqual( 1355 self.browser.url, self.contracts_path + '/%s/selectproduct' % conid) 1423 self.browser.url, 1424 self.contracts_path + '/%s/selectproduct' % conid) 1356 1425 # SAM is in the correct contract_category ... 1357 1426 self.assertTrue('<option value="SAM">' in self.browser.contents) … … 1359 1428 self.assertFalse('<option value="LIC">' in self.browser.contents) 1360 1429 # So far last_product_id is None. 1361 self.assertTrue(self.customer['contracts'][conid].last_product_id is None) 1430 self.assertTrue( 1431 self.customer['contracts'][conid].last_product_id is None) 1362 1432 self.browser.getControl(name="form.product_object").value = ['SAM'] 1363 1433 self.browser.getControl("Save and proceed").click() … … 1366 1436 # Document is a required field on edit form page. 1367 1437 self.browser.getControl("Save").click() 1368 self.assertTrue('Document: <span class="error">Required input is missing.</span>' 1438 self.assertTrue( 1439 'Document: <span class="error">Required input is missing.</span>' 1369 1440 in self.browser.contents) 1370 1441 # But our document can't be selected because it's not submitted … … 1376 1447 # After saving the form, last_product_id and other attributes are set 1377 1448 self.assertTrue('Form has been saved.' in self.browser.contents) 1378 self.assertEqual(self.customer['contracts'][conid].last_product_id, 'SAM') 1449 self.assertEqual( 1450 self.customer['contracts'][conid].last_product_id, 'SAM') 1379 1451 self.assertEqual(contract.title, 'Our Sample Product') 1380 1452 self.assertEqual(contract.product_object, self.product) … … 1382 1454 # Saving the form again does not unset last_product_id 1383 1455 self.browser.getControl("Save").click() 1384 self.assertEqual(self.customer['contracts'][conid].last_product_id, 'SAM') 1456 self.assertEqual( 1457 self.customer['contracts'][conid].last_product_id, 'SAM') 1385 1458 self.assertTrue('Form has been saved.' in self.browser.contents) 1386 1459 # So far we have not yet set product options. … … 1390 1463 prodoption.fee = Decimal('88.8') 1391 1464 prodoption.currency = 'EUR' 1392 contract.product_options = [prodoption, ]1465 contract.product_options = [prodoption, ] 1393 1466 self.browser.open(self.contracts_path + '/%s/edit' % conid) 1394 1467 # We can see both the stored and the recent product options 1395 1468 # from the chosen product. 1396 self.assertTrue('<option selected="selected" value="Any product option">' 1397 'Any product option @ 88.8 Euro</option>' 1398 in self.browser.contents) 1469 self.assertTrue( 1470 '<option selected="selected" value="Any product option">' 1471 'Any product option @ 88.8 Euro</option>' 1472 in self.browser.contents) 1399 1473 self.assertTrue('<option value="First option">First option ' 1400 1474 '@ 99.9 US Dollar</option>' in self.browser.contents) … … 1402 1476 self.browser.getControl( 1403 1477 name="form.product_options.0.").value = ['First option'] 1404 self.assertEqual(contract.product_options[0].title, 'Any product option') 1478 self.assertEqual( 1479 contract.product_options[0].title, 'Any product option') 1405 1480 self.browser.getControl("Save").click() 1406 1481 self.assertEqual(contract.product_options[0].title, 'First option') 1407 1482 self.browser.getLink("View").click() 1408 self.assertTrue('<span>First option @ 99.9 US Dollar</span>' in self.browser.contents) 1409 self.assertEqual(self.browser.url, self.contracts_path + '/%s/index' % conid) 1483 self.assertTrue( 1484 '<span>First option @ 99.9 US Dollar</span>' 1485 in self.browser.contents) 1486 self.assertEqual( 1487 self.browser.url, self.contracts_path + '/%s/index' % conid) 1410 1488 # An href attribute is referring to the document and product objects 1411 1489 self.assertTrue('<a href="http://localhost/app/products/SAM">SAM -' 1412 1490 in self.browser.contents) 1413 1491 self.assertTrue( 1414 '<a href="http://localhost/app/customers/K1000000/documents/DOC1">DOC1 -' 1492 '<a href="http://localhost/app/customers/K1000000/' 1493 'documents/DOC1">DOC1 -' 1415 1494 in self.browser.contents) 1416 1495 # Customer can submit the form if confirmation box is ticket. … … 1418 1497 self.browser.getLink("Edit").click() 1419 1498 self.browser.getControl("Proceed to checkout").click() 1420 self.assertTrue('confirm your acceptance of these by ticking' in self.browser.contents) 1499 self.assertTrue( 1500 'confirm your acceptance of these by ticking' 1501 in self.browser.contents) 1421 1502 self.assertEqual(contract.state, 'created') 1422 1503 self.browser.getControl(name="confirm_tc").value = True 1423 1504 self.browser.getControl("Proceed to checkout").click() 1424 1505 self.assertEqual(contract.state, 'created') 1506 radio_ctrl = self.browser.getControl(name='gw') 1507 radio_ctrl.value = [radio_ctrl.options[0]] # pick first payment opt 1425 1508 self.browser.getControl("Select payment method").click() 1426 1509 self.assertEqual(contract.state, 'awaiting') 1427 1510 # Customer can't edit the contract once it has been submitted 1428 1511 self.browser.open(self.contracts_path + '/%s/edit' % conid) 1429 self.assertTrue('The requested form is locked' in self.browser.contents) 1512 self.assertTrue( 1513 'The requested form is locked' in self.browser.contents) 1430 1514 1431 1515 def test_view_slips(self): … … 1435 1519 self.browser.getLink("Download contracts overview").click() 1436 1520 self.assertEqual(self.browser.headers['Status'], '200 Ok') 1437 self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf') 1521 self.assertEqual( 1522 self.browser.headers['Content-Type'], 'application/pdf') 1438 1523 path = os.path.join(samples_dir(), 'contracts_overview_slip.pdf') 1439 1524 open(path, 'wb').write(self.browser.contents) … … 1451 1536 self.browser.getLink("Download contract slip").click() 1452 1537 self.assertEqual(self.browser.headers['Status'], '200 Ok') 1453 self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf') 1538 self.assertEqual( 1539 self.browser.headers['Content-Type'], 'application/pdf') 1454 1540 path = os.path.join(samples_dir(), 'contract_slip.pdf') 1455 1541 open(path, 'wb').write(self.browser.contents) … … 1486 1572 # InvalidTransitionError is catched 1487 1573 self.assertTrue( 1488 '<div class="alert alert-warning">Attached documents must be verified first.</div>' 1574 '<div class="alert alert-warning">Attached documents ' 1575 'must be verified first.</div>' 1489 1576 in self.browser.contents) 1490 1577 self.browser.open(self.contracts_path + '/CON1/trigtrans') … … 1493 1580 self.browser.getControl("Apply").click() 1494 1581 self.assertEqual(IWorkflowState(self.contract).getState(), 'approved') 1582 1583 def test_select_payment(self): 1584 # select payment 1585 self.prepare_payment_select() 1586 self.browser.open('%s/CON1/edit' % self.contracts_path) 1587 self.browser.getControl("Proceed to checkout").click() 1588 self.assertTrue( 1589 "Select payment method" in self.browser.contents) 1590 self.assertTrue( 1591 'Credit Card (Demo Payments)' in self.browser.contents) 1592 1593 def test_select_payment_no_choice(self): 1594 # we get warned if no payment was selected 1595 self.prepare_payment_select() 1596 self.browser.open( 1597 '%s/CON1/select_payment_method' % self.contracts_path) 1598 self.browser.getControl(self.never_ending_button_text).click() 1599 self.assertTrue( 1600 'Please pick a payment method' in self.browser.contents) 1601 1602 def test_select_payment_demo_provider(self): 1603 # we can proceed with payments if we select a payment method 1604 self.prepare_payment_select() 1605 self.browser.open( 1606 '%s/CON1/select_payment_method' % self.contracts_path) 1607 radio_ctrl = self.browser.getControl(name='gw') 1608 radio_ctrl.displayValue = ['Credit Card (Demo Payments)'] 1609 self.browser.getControl(self.never_ending_button_text).click() -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_contract.py
r12259 r12741 19 19 Tests for contracts. 20 20 """ 21 import decimal 21 22 from zope.interface.verify import verifyClass, verifyObject 22 from zope.component import createObject 23 from zope.component import createObject, getUtility, getUtilitiesFor 24 from zope.component.hooks import setSite 23 25 from hurry.workflow.interfaces import ( 24 26 IWorkflowInfo, IWorkflowState, InvalidTransitionError) 25 27 from waeup.ikoba.customers.interfaces import ( 26 28 IContractsContainer, IContract) 27 from waeup.ikoba.interfaces import IObjectHistory28 29 from waeup.ikoba.customers.contracts import ( 29 ContractsContainer, SampleContract) 30 ContractsContainer, SampleContract, ContractPayer, ContractFinder, 31 PayableContract, 32 ) 33 from waeup.ikoba.app import Company 34 from waeup.ikoba.customers.customer import Customer 35 from waeup.ikoba.payments.interfaces import ( 36 IPaymentItem, IPayer, IPayableFinder, IPayable, 37 ) 38 from waeup.ikoba.products.productoptions import ProductOption 30 39 from waeup.ikoba.testing import (FunctionalLayer, FunctionalTestCase) 40 31 41 32 42 class ContractsContainerTestCase(FunctionalTestCase): … … 89 99 self.assertTrue('Contract created by system' in messages) 90 100 return 101 102 103 class TestContractHelpers(FunctionalTestCase): 104 105 layer = FunctionalLayer 106 107 def test_payer_adapter(self): 108 # we can adapt IContract to IPayer (i.e. create a payer) 109 customer = Customer() 110 customer.firstname, customer.lastname = u'Anna', u'Tester' 111 contract = createObject(u'waeup.SampleContract') 112 customer['contracts'] = ContractsContainer() 113 customer['contracts'].addContract(contract) 114 result = IPayer(contract) 115 self.assertTrue(isinstance(result, ContractPayer)) 116 verifyObject(IPayer, result) 117 self.assertEqual(result.first_name, u'Anna') 118 self.assertEqual(result.last_name, u'Tester') 119 self.assertEqual(result.payer_id, customer.customer_id) 120 121 def test_contract_finder_iface(self): 122 # we have a contract finder that returns IPayableFinder data. 123 verifyClass(IPayableFinder, ContractFinder) 124 125 def test_contract_finder_registered(self): 126 # the contract finder is a utility registered on startup 127 util = getUtility(IPayableFinder, name='contracts_finder') 128 self.assertTrue(isinstance(util, ContractFinder)) 129 utils = [util for name, util in getUtilitiesFor(IPayableFinder) 130 if isinstance(util, ContractFinder)] 131 self.assertEqual(len(utils), 1) 132 133 def create_contract_and_site(self): 134 contract = SampleContract() 135 option1 = ProductOption(u"Fee 1", decimal.Decimal("31.10"), "USD") 136 option2 = ProductOption(u"Fee 2", decimal.Decimal("12.12"), "USD") 137 contract.product_options = [option1, option2] 138 contract.contract_id = u'CON1234' 139 self.getRootFolder()['app'] = Company() 140 app = self.getRootFolder()['app'] 141 setSite(app) 142 return contract, app 143 144 def test_contract_finder(self): 145 # the contract finder can really find contracts 146 contract, app = self.create_contract_and_site() 147 app['mycontract'] = contract # trigger cataloging 148 finder = ContractFinder() 149 result = finder.get_payable_by_id('CON1234') 150 self.assertTrue(result is contract) 151 152 def test_contract_finder_not_stored(self): 153 # we get none if an id is not stored 154 contract, app = self.create_contract_and_site() 155 app['mycontract'] = contract # trigger cataloging 156 finder = ContractFinder() 157 result = finder.get_payable_by_id('Not-a-valid-id') 158 self.assertTrue(result is None) 159 160 def test_contract_finder_no_catalog(self): 161 # contract finder does not complain about missing catalog 162 finder = ContractFinder() 163 result = finder.get_payable_by_id('CON1234') 164 self.assertTrue(result is None) 165 166 167 class TestContractAsPayable(FunctionalTestCase): 168 169 layer = FunctionalLayer 170 171 def test_adaptable(self): 172 # we can turn contracts into payables. 173 contract = SampleContract() 174 payable = IPayable(contract) 175 self.assertTrue(payable is not None) 176 self.assertTrue(isinstance(payable, PayableContract)) 177 178 def test_payable_iface(self): 179 # PayableContracts really provide IPayable 180 contract = SampleContract() 181 option1 = ProductOption(u"Fee 1", decimal.Decimal("31.10"), "USD") 182 option2 = ProductOption(u"Fee 2", decimal.Decimal("12.12"), "USD") 183 contract.product_options = [option1, option2] 184 payable = PayableContract(contract) 185 verifyObject(IPayable, payable) 186 verifyClass(IPayable, PayableContract) 187 188 def test_payable_simple_attributes(self): 189 # the simple attribs are set correctly, according to context contract 190 contract = SampleContract() 191 contract.title = u'the title' 192 option1 = ProductOption(u"Fee 1", decimal.Decimal("31.10"), "EUR") 193 option2 = ProductOption(u"Fee 2", decimal.Decimal("12.12"), "EUR") 194 contract.product_options = [option1, option2] 195 payable = PayableContract(contract) 196 self.assertTrue(contract.contract_id, payable.payable_id) 197 self.assertEqual(payable.title, contract.title) 198 self.assertEqual(payable.currency, 'EUR') 199 200 def test_payable_items(self): 201 # we can get payment items from payable 202 contract = SampleContract() 203 option1 = ProductOption(u"Fee 1", decimal.Decimal("31.10"), "EUR") 204 option2 = ProductOption(u"Fee 2", decimal.Decimal("12.12"), "EUR") 205 contract.product_options = [option1, option2] 206 payable = PayableContract(contract) 207 items = payable.payment_items 208 self.assertTrue(isinstance(items, tuple)) 209 self.assertEqual(len(items), 2) 210 verifyObject(IPaymentItem, items[0]) 211 verifyObject(IPaymentItem, items[1]) 212 self.assertEqual(items[0].item_id, '0') 213 self.assertEqual(items[0].title, u'Fee 1') 214 self.assertEqual(items[0].amount, decimal.Decimal("31.10")) 215 216 def test_payable_no_items(self): 217 # payables work also with no options set on contract 218 contract = SampleContract() 219 payable = PayableContract(contract) 220 items = payable.payment_items 221 self.assertTrue(isinstance(items, tuple)) 222 self.assertEqual(len(items), 0) 223 self.assertEqual(payable.currency, None) 224 225 def test_different_currencies_forbiddedn(self): 226 # we do not accept different currencies in payment items 227 contract = SampleContract() 228 option1 = ProductOption(u"Fee 1", decimal.Decimal("31.10"), "EUR") 229 option2 = ProductOption(u"Fee 2", decimal.Decimal("12.12"), "USD") 230 contract.product_options = [option1, option2] 231 self.assertRaises(ValueError, PayableContract, contract) -
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_customer.py
r12297 r12741 21 21 import re 22 22 import unittest 23 import grok24 23 from cStringIO import StringIO 25 from datetime import tzinfo 26 from zope.component import getUtility, queryUtility, createObject 27 from zope.catalog.interfaces import ICatalog 24 from zope.component import getUtility, getUtilitiesFor 25 from zope.component.hooks import setSite 28 26 from zope.component.interfaces import IFactory 29 from zope.event import notify30 27 from zope.interface import verify 31 from zope.schema.interfaces import RequiredMissing32 28 from waeup.ikoba.interfaces import IExtFileStore, IFileStoreNameChooser 29 from waeup.ikoba.app import Company 33 30 from waeup.ikoba.customers.customer import ( 34 Customer, CustomerFactory, handle_customer_removed, path_from_custid) 31 Customer, CustomerFactory, handle_customer_removed, path_from_custid, 32 CustomerPayer, CustomerFinder, 33 ) 35 34 from waeup.ikoba.customers.interfaces import ( 36 35 ICustomer, ICustomerNavigation, ICustomersUtils) 37 36 from waeup.ikoba.customers.tests.test_batching import CustomerImportExportSetup 37 from waeup.ikoba.payments.interfaces import IPayer, IPayerFinder 38 38 from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase 39 39 40 40 41 class HelperTests(unittest.TestCase): … … 59 60 path_from_custid('KM123456'), u'00120/KM123456') 60 61 return 62 61 63 62 64 class CustomerTest(FunctionalTestCase): … … 92 94 93 95 96 class TestCustomerHelpers(FunctionalTestCase): 97 98 layer = FunctionalLayer 99 100 def test_payer_adapter(self): 101 # we can adapt ICustomer to IPayer (i.e. create a payer) 102 customer = Customer() 103 customer.firstname, customer.lastname = u'Anna', u'Tester' 104 result = IPayer(customer) 105 self.assertTrue(isinstance(result, CustomerPayer)) 106 verify.verifyObject(IPayer, result) 107 self.assertEqual(result.first_name, u'Anna') 108 self.assertEqual(result.last_name, u'Tester') 109 self.assertEqual(result.payer_id, customer.customer_id) 110 111 def test_customer_finder_iface(self): 112 # we have a customer finder that returns IPayableFinder data. 113 verify.verifyClass(IPayerFinder, CustomerFinder) 114 115 def test_customer_finder_registered(self): 116 # the customer finder is a utility registered on startup 117 util = getUtility(IPayerFinder, name='customer_finder') 118 self.assertTrue(isinstance(util, CustomerFinder)) 119 utils = [util for name, util in getUtilitiesFor(IPayerFinder) 120 if isinstance(util, CustomerFinder)] 121 self.assertEqual(len(utils), 1) 122 123 def create_customer_and_site(self): 124 customer = Customer() 125 customer.customer_id = u'CUST1' 126 self.getRootFolder()['app'] = Company() 127 app = self.getRootFolder()['app'] 128 setSite(app) 129 return customer, app 130 131 def test_customer_finder(self): 132 # the customer finder can really find customers 133 customer, app = self.create_customer_and_site() 134 app['mycustomer'] = customer # trigger cataloging 135 finder = CustomerFinder() 136 result = finder.get_payer_by_id('CUST1') 137 self.assertTrue(result is customer) 138 139 def test_customer_finder_not_stored(self): 140 # we get none if an id is not stored 141 customer, app = self.create_customer_and_site() 142 app['mycustomer'] = customer # trigger cataloging 143 finder = CustomerFinder() 144 result = finder.get_payer_by_id('Not-a-valid-id') 145 self.assertTrue(result is None) 146 147 def test_customer_finder_no_catalog(self): 148 # customer finder does not complain about missing catalog 149 finder = CustomerFinder() 150 result = finder.get_payer_by_id('CUST1') 151 self.assertTrue(result is None) 152 153 94 154 class CustomerRemovalTests(CustomerImportExportSetup): 95 155 # Test handle_customer_removed … … 192 252 return 193 253 254 194 255 class CustomerFactoryTest(FunctionalTestCase): 195 256
Note: See TracChangeset for help on using the changeset viewer.