source: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/contracts.py @ 12682

Last change on this file since 12682 was 12681, checked in by uli, 10 years ago

pep8, pyflakes.

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