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

Last change on this file since 12731 was 12728, checked in by uli, 10 years ago

Remove obsolete func.

  • Property svn:keywords set to Id
File size: 9.1 KB
RevLine 
[12089]1## $Id: contracts.py 12728 2015-03-11 10:16:58Z 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"""
[12097]19Customer contract components.
[12089]20"""
21import grok
[12716]22from zope.catalog.interfaces import ICatalog
[12718]23from zope.component import getUtility, queryUtility
[12089]24from zope.component.interfaces import IFactory
25from zope.interface import implementedBy
[12144]26from zope.schema import getFields
[12089]27from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
28from waeup.ikoba.interfaces import MessageFactory as _
[12258]29from waeup.ikoba.interfaces import (
[12681]30    IObjectHistory, VERIFIED, APPROVED, PROVISIONALLY, IIDSource)
[12089]31from waeup.ikoba.customers.interfaces import (
[12681]32    IContractsContainer, ICustomerNavigation, IContract,
33    IContractSelectProduct, ICustomersUtils, ISampleContract,
34    ISampleContractProcess, ISampleContractEdit, ISampleContractOfficialUse)
[12727]35from waeup.ikoba.payments.interfaces import IPayer, IPayableFinder, IPayable
[12683]36from waeup.ikoba.payments.payment import PaymentItem
[12089]37from waeup.ikoba.utils.helpers import attrs_to_fields
38
[12681]39
[12097]40class ContractsContainer(grok.Container):
41    """This is a container for customer contracts.
[12089]42    """
[12097]43    grok.implements(IContractsContainer, ICustomerNavigation)
44    grok.provides(IContractsContainer)
[12089]45
[12097]46    def addContract(self, contract):
47        if not IContract.providedBy(contract):
[12089]48            raise TypeError(
[12097]49                'ContractsContainers contain only IContract instances')
50        self[contract.contract_id] = contract
[12089]51        return
52
53    @property
54    def customer(self):
55        return self.__parent__
56
57    def writeLogMessage(self, view, message):
58        return self.__parent__.writeLogMessage(view, message)
59
[12097]60ContractsContainer = attrs_to_fields(ContractsContainer)
[12089]61
[12681]62
[12697]63class ContractPayer(grok.Adapter):
64    """Adapter to turn contracts into IPayers.
65    """
66    grok.implements(IPayer)
67    grok.context(IContract)
68
69    def __init__(self, context):
70        self.context = context
71
72    @property
73    def _customer(self):
74        return self.context.customer
75
76    @property
77    def first_name(self):
78        return getattr(self._customer, 'firstname', None)
79
80    @property
81    def last_name(self):
82        return getattr(self._customer, 'lastname', None)
83
84    @property
85    def payer_id(self):
86        return getattr(self._customer, 'customer_id', None)
87
88
[12097]89class ContractBase(grok.Container):
90    """This is a customer contract baseclass.
[12089]91    """
[12681]92    grok.implements(IContractSelectProduct)  # Neccessary for the
93                                             # selectproduct page (why?)
[12089]94    grok.baseclass()
95
96    def __init__(self):
[12097]97        super(ContractBase, self).__init__()
[12089]98        # The site doesn't exist in unit tests
[12258]99        source = getUtility(IIDSource)
100        self.contract_id = unicode(source.get_hex_uuid())
[12094]101        self.last_product_id = None
[12363]102        self.tc_dict = {}
[12580]103        self.title = None
[12633]104        self.valid_to = None
105        self.valid_from = None
[12089]106        return
107
108    @property
109    def history(self):
110        history = IObjectHistory(self)
111        return history
112
113    @property
114    def state(self):
115        return IWorkflowState(self).getState()
116
117    @property
118    def translated_state(self):
119        try:
120            TRANSLATED_STATES = getUtility(
[12097]121                ICustomersUtils).TRANSLATED_CONTRACT_STATES
[12089]122            return TRANSLATED_STATES[self.state]
123        except KeyError:
124            return
125
126    @property
127    def class_name(self):
128        return self.__class__.__name__
129
130    @property
131    def formatted_transition_date(self):
132        try:
[12210]133            return self.history.messages[-1].split(' - ')[0]
134        except IndexError:
[12089]135            return
136
137    @property
138    def customer(self):
139        try:
140            return self.__parent__.__parent__
141        except AttributeError:
142            return None
143
[12289]144    @property
145    def user_id(self):
146        if self.customer is not None:
147            return self.customer.customer_id
148        return
149
[12089]150    def writeLogMessage(self, view, message):
151        return self.__parent__.__parent__.writeLogMessage(view, message)
152
153    @property
[12337]154    def is_editable(self):
[12089]155        try:
[12573]156            # Customer must have requested
[12089]157            cond1 = self.customer.state in getUtility(
[12099]158                ICustomersUtils).CONMANAGE_CUSTOMER_STATES
[12097]159            # Contract must be in state created
[12089]160            cond2 = self.state in getUtility(
[12099]161                ICustomersUtils).CONMANAGE_CONTRACT_STATES
[12089]162            if not (cond1 and cond2):
163                return False
164        except AttributeError:
165            pass
166        return True
167
168    @property
[12144]169    def is_approvable(self):
[12573]170        if self.customer and not self.customer.state in (
171            APPROVED, PROVISIONALLY):
[12352]172            return False, _("Customer has not yet been approved.")
[12144]173        for key, field in getFields(self.check_docs_interface).items():
174            if key.endswith('_object'):
175                obj = getattr(self, key, None)
176                state = getattr(obj, 'state', None)
177                if state and state != VERIFIED:
[12681]178                    return False, _(
179                        "Attached documents must be verified first.")
[12168]180        return True, None
[12144]181
182    @property
[12089]183    def translated_class_name(self):
184        try:
[12099]185            CONTYPES_DICT = getUtility(ICustomersUtils).CONTYPES_DICT
186            return CONTYPES_DICT[self.class_name]
[12089]187        except KeyError:
188            return
189
[12663]190    @property
191    def fee_based(self):
192        if self.product_options:
193            amount = 0
194            for option in self.product_options:
195                amount += option.fee
196            if amount:
197                return True
198        return False
[12089]199
[12663]200
[12097]201class SampleContract(ContractBase):
202    """This is a sample contract.
[12089]203    """
204
[12333]205    grok.implements(
[12681]206        ISampleContractProcess,  # must come before ISampleContract
[12333]207        ISampleContract,
208        ISampleContractEdit,
209        ICustomerNavigation)
[12103]210
[12097]211    contract_category = 'sample'
[12092]212
[12103]213    form_fields_interface = ISampleContract
214
215    edit_form_fields_interface = ISampleContractEdit
216
[12500]217    ou_form_fields_interface = ISampleContractOfficialUse
218
[12144]219    check_docs_interface = ISampleContract
220
[12097]221SampleContract = attrs_to_fields(SampleContract)
[12089]222
223
[12097]224# Contracts must be importable. So we might need a factory.
225class SampleContractFactory(grok.GlobalUtility):
226    """A factory for contracts.
[12089]227    """
228    grok.implements(IFactory)
[12097]229    grok.name(u'waeup.SampleContract')
230    title = u"Create a new contract.",
231    description = u"This factory instantiates new sample contract instances."
[12089]232
233    def __call__(self, *args, **kw):
[12097]234        return SampleContract(*args, **kw)
[12089]235
236    def getInterfaces(self):
[12097]237        return implementedBy(SampleContract)
[12089]238
[12681]239
[12097]240@grok.subscribe(IContract, grok.IObjectAddedEvent)
241def handle_contract_added(contract, event):
242    """If an contract is added the transition create is fired.
[12090]243    The latter produces a logging message.
244    """
[12097]245    if IWorkflowState(contract).getState() is None:
246        IWorkflowInfo(contract).fireTransition('create')
[12090]247    return
[12716]248
249
250class ContractFinder(grok.GlobalUtility):
251    grok.name('contracts_finder')
252    grok.implements(IPayableFinder)
253
[12717]254    def get_payable_by_id(self, contract_id):
[12718]255        catalog = queryUtility(ICatalog, 'contracts_catalog')
256        if catalog is None:
257            return None
[12716]258        result = catalog.searchResults(
259            contract_id=(contract_id, contract_id))
260        result = [x for x in result]
261        if not result:
262            return None
263        # there should not be more than one result really.
264        return result[0]
[12727]265
266
267class PayableContract(grok.Adapter):
268    """Adapter to adapt IContracts to IPayable.
269    """
270
271    grok.context(IContract)
272    grok.implements(IPayable)
273
274    def __init__(self, context):
275        self.context = context
276        currencies = set([x.currency for x in context.product_options])
277        if len(currencies) > 1:
278            raise ValueError(
279                "Only contracts with same currency for all options allowed.")
280        return
281
282    @property
283    def payable_id(self):
284        return self.context.contract_id
285
286    @property
287    def title(self):
288        return self.context.title
289
290    @property
291    def currency(self):
292        if not len(self.context.product_options):
293            return None
294        return self.context.product_options[0].currency
295
296    @property
297    def payment_items(self):
298        result = []
299        for num, option in enumerate(self.context.product_options):
300            item = PaymentItem()
301            item.item_id = u'%s' % num
302            item.title = option.title
303            item.amount = option.fee
304            result.append(item)
305        return tuple(result)
Note: See TracBrowser for help on using the repository browser.