source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/export.py @ 12432

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

Improve contract management. Tests will follow which show that customers can only do what they are allowed to do.

  • Property svn:keywords set to Id
File size: 8.1 KB
RevLine 
[12006]1## $Id: export.py 12337 2014-12-29 23:05:40Z henrik $
[11958]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"""Exporters for customer related stuff.
19"""
20import os
21import grok
22from datetime import datetime
23from zope.component import getUtility
24from waeup.ikoba.interfaces import (
[12032]25    IExtFileStore, IFileStoreNameChooser)
[11958]26from waeup.ikoba.interfaces import MessageFactory as _
27from waeup.ikoba.customers.catalog import CustomersQuery
28from waeup.ikoba.customers.interfaces import (
[12279]29    ICustomer, ICSVCustomerExporter,
30    ICustomerSampleDocument, ISampleContract)
[11958]31from waeup.ikoba.utils.batching import ExporterBase
32from waeup.ikoba.utils.helpers import iface_names, to_timezone
33
34def get_customers(site, cust_filter=CustomersQuery()):
35    """Get all customers registered in catalog in `site`.
36    """
37    return cust_filter.query()
38
[12279]39def get_documents(customers, class_name):
[12006]40    """Get all documents of `customers`.
41    """
42    documents = []
43    for customer in customers:
44        for document in customer.get('documents', {}).values():
[12279]45            if document.class_name == class_name:
46                documents.append(document)
[12006]47    return documents
[11985]48
[12279]49def get_contracts(customers, class_name):
[12143]50    """Get all contracts of `customers`.
51    """
52    contracts = []
53    for customer in customers:
54        for contract in customer.get('contracts', {}).values():
[12279]55            if contract.class_name == class_name:
56                contracts.append(contract)
[12143]57    return contracts
[12006]58
[11958]59class CustomerExporterBase(ExporterBase):
60    """Exporter for customers or related objects.
61
62    This is a baseclass.
63    """
64    grok.baseclass()
65    grok.implements(ICSVCustomerExporter)
66    grok.provides(ICSVCustomerExporter)
67
68    def filter_func(self, x, **kw):
69        return x
70
71    def get_filtered(self, site, **kw):
72        """Get customers from a catalog filtered by keywords.
73
74        customers_catalog is the default catalog. The keys must be valid
75        catalog index names.
76        Returns a simple empty list, a list with `Customer`
77        objects or a catalog result set with `Customer`
78        objects.
79
80        .. seealso:: `waeup.ikoba.customers.catalog.CustomersCatalog`
81
82        """
83        # Pass only given keywords to create FilteredCatalogQuery objects.
84        # This way we avoid
85        # trouble with `None` value ambivalences and queries are also
86        # faster (normally less indexes to ask). Drawback is, that
87        # developers must look into catalog to see what keywords are
88        # valid.
89        query = CustomersQuery(**kw)
90        return query.query()
91
92    def export(self, values, filepath=None):
93        """Export `values`, an iterable, as CSV file.
94
95        If `filepath` is ``None``, a raw string with CSV data is returned.
96        """
97        writer, outfile = self.get_csv_writer(filepath)
98        for value in values:
99            self.write_item(value, writer)
100        return self.close_outfile(filepath, outfile)
101
102    def export_all(self, site, filepath=None):
103        """Export customers into filepath as CSV data.
104
105        If `filepath` is ``None``, a raw string with CSV data is returned.
106        """
107        return self.export(self.filter_func(get_customers(site)), filepath)
108
109    def export_customer(self, customer, filepath=None):
110        return self.export(self.filter_func([customer]), filepath=filepath)
111
112    def export_filtered(self, site, filepath=None, **kw):
113        """Export items denoted by `kw`.
114
115        If `filepath` is ``None``, a raw string with CSV data should
116        be returned.
117        """
118        data = self.get_filtered(site, **kw)
119        return self.export(self.filter_func(data, **kw), filepath=filepath)
120
121
[12076]122class CustomerExporter(grok.GlobalUtility, CustomerExporterBase):
[11958]123    """Exporter for Customers.
124    """
125    grok.name('customers')
126
[12275]127    iface = ICustomer
[11958]128
129    #: The title under which this exporter will be displayed
130    title = _(u'Customers')
131
[12275]132    #: Fieldnames considered by this exporter
133    @property
134    def fields(self):
135        return tuple(sorted(iface_names(self.iface))) + (
136            'password', 'state', 'history',)
137
[11958]138    def mangle_value(self, value, name, context=None):
139        if name == 'history':
140            value = value.messages
141        if name == 'phone' and value is not None:
142            # Append hash '#' to phone numbers to circumvent
143            # unwanted excel automatic
144            value = str('%s#' % value)
145        return super(
[12076]146            CustomerExporter, self).mangle_value(
[11958]147            value, name, context=context)
[12006]148
[12143]149
[12279]150class CustomerDocumentExporterBase(grok.GlobalUtility, CustomerExporterBase):
151    """Exporter for Customer Document instances.
152
153    This is a baseclass.
[12006]154    """
[12279]155    grok.baseclass()
156    iface = None
157    class_name = None
158    title = None
[12006]159
[12275]160    #: Fieldnames considered by this exporter
161    @property
162    def fields(self):
163        return tuple(
164            sorted(iface_names(
165                self.iface, exclude_attribs=False,
166                omit=['is_editable_by_customer',
167                      'is_editable_by_manager',
168                      'is_verifiable',
169                      'translated_state',
170                      'formatted_transition_date',
171                      'translated_class_name',
172                      'connected_files',   # Could be used to export file URLs
173                      ])))
174
[12006]175    def filter_func(self, x, **kw):
[12279]176        return get_documents(x, self.class_name)
[12006]177
178    def mangle_value(self, value, name, context=None):
[12143]179
[12007]180        if name == 'history':
181            value = value.messages
[12006]182        return super(
[12279]183            CustomerDocumentExporterBase, self).mangle_value(
[12006]184            value, name, context=context)
[12143]185
186
[12279]187class CustomerSampleDocumentExporter(CustomerDocumentExporterBase):
188    """Exporter for CustomerSampleDocument instances.
[12143]189    """
[12279]190    grok.name('customersampledocuments')
[12143]191
[12279]192    iface = ICustomerSampleDocument
193    class_name = 'CustomerSampleDocument'
194    title = _(u'Customer Sample Documents')
[12143]195
196
[12280]197class ContractExporterBase(grok.GlobalUtility, CustomerExporterBase):
[12279]198    """Exporter for Contract instances.
199
200    This is a baseclass.
201    """
202    grok.baseclass()
203    iface = None
204    class_name = None
205    title = None
206
[12275]207    #: Fieldnames considered by this exporter
208    @property
209    def fields(self):
210        return tuple(
211            sorted(iface_names(
212                self.iface, exclude_attribs=False,
213                omit=['translated_state',
214                      'formatted_transition_date',
215                      'translated_class_name',
[12337]216                      'is_editable',
[12275]217                      'is_approvable'])))
218
[12143]219    def filter_func(self, x, **kw):
[12279]220        return get_contracts(x, self.class_name)
[12143]221
222    def mangle_value(self, value, name, context=None):
223
224        if name == 'history':
225            value = value.messages
226        if name.endswith('_object'):
227            mangled_value = getattr(value, 'document_id', None)
228            if mangled_value:
229                return mangled_value
230            mangled_value = getattr(value, 'product_id', None)
231            if mangled_value:
232                return mangled_value
[12330]233        if name == 'product_options' and value is not None:
234            value = [eval(entry.to_string()) for entry in value]
[12143]235        return super(
[12280]236            ContractExporterBase, self).mangle_value(
[12143]237            value, name, context=context)
[12279]238
239
[12280]240class SampleContractExporter(ContractExporterBase):
[12279]241    """Exporter for sample contracts.
242    """
243    grok.name('samplecontracts')
244    iface = ISampleContract
245    class_name = 'SampleContract'
[12283]246    title = _(u'Customer Sample Contracts')
Note: See TracBrowser for help on using the repository browser.