source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/contracts.py @ 12356

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

Customers must have been approved before verifying documents or approving contracts.

  • Property svn:keywords set to Id
File size: 6.6 KB
Line 
1## $Id: contracts.py 12352 2014-12-31 13:38:50Z 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"""
19Customer contract components.
20"""
21import os
22import grok
23from zope.component import queryUtility, getUtility
24from zope.component.interfaces import IFactory
25from zope.interface import implementedBy
26from zope.schema import getFields
27from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
28from waeup.ikoba.interfaces import MessageFactory as _
29from waeup.ikoba.interfaces import (
30    IIkobaUtils, IObjectHistory, VERIFIED, IIDSource)
31from waeup.ikoba.customers.interfaces import (
32    IContractsContainer, ICustomerNavigation,
33    IContract, IContractProcess, IContractEdit, ICustomersUtils,
34    ISampleContract, ISampleContractProcess, ISampleContractEdit)
35from waeup.ikoba.customers.utils import generate_contract_id
36from waeup.ikoba.utils.helpers import attrs_to_fields
37
38class ContractsContainer(grok.Container):
39    """This is a container for customer contracts.
40    """
41    grok.implements(IContractsContainer, ICustomerNavigation)
42    grok.provides(IContractsContainer)
43
44    def addContract(self, contract):
45        if not IContract.providedBy(contract):
46            raise TypeError(
47                'ContractsContainers contain only IContract instances')
48        self[contract.contract_id] = contract
49        return
50
51    @property
52    def customer(self):
53        return self.__parent__
54
55    def writeLogMessage(self, view, message):
56        return self.__parent__.writeLogMessage(view, message)
57
58ContractsContainer = attrs_to_fields(ContractsContainer)
59
60class ContractBase(grok.Container):
61    """This is a customer contract baseclass.
62    """
63    grok.implements(IContractEdit)  # Necesary for the selectproduct page
64
65    grok.baseclass()
66
67    check_docs_interface = None
68
69    contract_category = None
70
71    form_fields_interface = None
72
73    edit_form_fields_interface = None
74
75    def __init__(self):
76        super(ContractBase, self).__init__()
77        # The site doesn't exist in unit tests
78        source = getUtility(IIDSource)
79        self.contract_id = unicode(source.get_hex_uuid())
80        self.last_product_id = None
81        return
82
83    @property
84    def history(self):
85        history = IObjectHistory(self)
86        return history
87
88    @property
89    def state(self):
90        return IWorkflowState(self).getState()
91
92    @property
93    def translated_state(self):
94        try:
95            TRANSLATED_STATES = getUtility(
96                ICustomersUtils).TRANSLATED_CONTRACT_STATES
97            return TRANSLATED_STATES[self.state]
98        except KeyError:
99            return
100
101    @property
102    def class_name(self):
103        return self.__class__.__name__
104
105    @property
106    def formatted_transition_date(self):
107        try:
108            return self.history.messages[-1].split(' - ')[0]
109        except IndexError:
110            return
111
112    @property
113    def title(self):
114        return getattr(
115            getattr(self, 'product_object', None),
116            'contract_autotitle', None)
117
118    @property
119    def customer(self):
120        try:
121            return self.__parent__.__parent__
122        except AttributeError:
123            return None
124
125    @property
126    def user_id(self):
127        if self.customer is not None:
128            return self.customer.customer_id
129        return
130
131    def writeLogMessage(self, view, message):
132        return self.__parent__.__parent__.writeLogMessage(view, message)
133
134    @property
135    def is_editable(self):
136        try:
137            # Customer must be approved
138            cond1 = self.customer.state in getUtility(
139                ICustomersUtils).CONMANAGE_CUSTOMER_STATES
140            # Contract must be in state created
141            cond2 = self.state in getUtility(
142                ICustomersUtils).CONMANAGE_CONTRACT_STATES
143            if not (cond1 and cond2):
144                return False
145        except AttributeError:
146            pass
147        return True
148
149    @property
150    def is_approvable(self):
151        if self.customer and not self.customer.state in getUtility(
152                ICustomersUtils).CONMANAGE_CUSTOMER_STATES:
153            return False, _("Customer has not yet been approved.")
154        for key, field in getFields(self.check_docs_interface).items():
155            if key.endswith('_object'):
156                obj = getattr(self, key, None)
157                state = getattr(obj, 'state', None)
158                if state and state != VERIFIED:
159                    return False, _("Attached documents must be verified first.")
160        return True, None
161
162    @property
163    def translated_class_name(self):
164        try:
165            CONTYPES_DICT = getUtility(ICustomersUtils).CONTYPES_DICT
166            return CONTYPES_DICT[self.class_name]
167        except KeyError:
168            return
169
170
171class SampleContract(ContractBase):
172    """This is a sample contract.
173    """
174
175    grok.implements(
176        ISampleContractProcess, # must come before ISampleContract
177        ISampleContract,
178        ISampleContractEdit,
179        ICustomerNavigation)
180
181    contract_category = 'sample'
182
183    form_fields_interface = ISampleContract
184
185    edit_form_fields_interface = ISampleContractEdit
186
187    check_docs_interface = ISampleContract
188
189SampleContract = attrs_to_fields(SampleContract)
190
191
192# Contracts must be importable. So we might need a factory.
193class SampleContractFactory(grok.GlobalUtility):
194    """A factory for contracts.
195    """
196    grok.implements(IFactory)
197    grok.name(u'waeup.SampleContract')
198    title = u"Create a new contract.",
199    description = u"This factory instantiates new sample contract instances."
200
201    def __call__(self, *args, **kw):
202        return SampleContract(*args, **kw)
203
204    def getInterfaces(self):
205        return implementedBy(SampleContract)
206
207@grok.subscribe(IContract, grok.IObjectAddedEvent)
208def handle_contract_added(contract, event):
209    """If an contract is added the transition create is fired.
210    The latter produces a logging message.
211    """
212    if IWorkflowState(contract).getState() is None:
213        IWorkflowInfo(contract).fireTransition('create')
214    return
Note: See TracBrowser for help on using the repository browser.