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

Last change on this file since 12696 was 12683, checked in by uli, 10 years ago

Add adapter to turn lists of product opitons into payment items.

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