## $Id: contract_statistics.py 12663 2015-03-05 07:28:31Z henrik $ ## ## Copyright (C) 2015 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## import grok from zope.i18n import translate from zope.catalog.interfaces import ICatalog from zope.component import queryUtility, getUtility from zope.interface import implementer, Interface, Attribute from waeup.ikoba.interfaces import ( IIkobaUtils, CREATED, APPROVED, SUBMITTED, EXPIRED, REJECTED, AWAITING) from waeup.ikoba.customers.interfaces import ICustomersUtils from waeup.ikoba.interfaces import MessageFactory as _ from waeup.ikoba.reports import IReport class IContractStatisticsReport(IReport): creation_dt_string = Attribute('Human readable report creation datetime') def get_contract_stats(): """Get contracts Returns a table ordered by contract type and contract state (cols). The result is a 3-tuple representing ((), (), ()). The () is an n-tuple with each entry containing the number of contracts found for that type and with the respective state. Sample result: >>> ((u'Sample Contract 1', u'Sample Contract 2'), ... ('created', 'submitted for approval', 'approved'), ... ((12, 10, 1), (0, 5, 25))) This result means: there are 5 contracts of type 'Sample Contract 2' are in state 'submitted'. """ site = grok.getSite() TYPES = getUtility(ICustomersUtils).CONTYPES_DICT types = TYPES.keys() type_names = tuple(TYPES.values()) + (u'All',) states = (CREATED, AWAITING, SUBMITTED, APPROVED, EXPIRED, REJECTED) STATES = getUtility(ICustomersUtils).TRANSLATED_CONTRACT_STATES state_names = tuple([STATES[state] for state in states]) + (u'Total',) # find all contracts cat = queryUtility(ICatalog, name="contracts_catalog") contracts = cat.searchResults(contract_id=(None, None)) # create empty table table = [[0 for x in xrange(len(STATES)+1)] for y in xrange(len(TYPES)+1)] # fill table for contract in contracts: row = types.index(contract.class_name) col = states.index(contract.state) table[row][col] += 1 table[-1][col] += 1 table[row][-1] += 1 table[-1][-1] += 1 # turn lists into tuples table = tuple([tuple(row) for row in table]) return (type_names, state_names, table) from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.units import cm from reportlab.platypus import Paragraph, Table, Spacer from waeup.ikoba.reports import IReport, IReportGenerator from waeup.ikoba.reports import Report from waeup.ikoba.browser.interfaces import IPDFCreator STYLE = getSampleStyleSheet() def tbl_data_to_table(row_names, col_names, data): result = [] new_col_names = [] for name in col_names: new_col_names.append(name.replace(' ', '\n')) head = [''] + list(new_col_names) result = [head] for idx, row_name in enumerate(row_names): row = [row_name] + list(data[idx]) result.append(row) return result TABLE_STYLE = [ ('FONT', (0,0), (-1,-1), 'Helvetica', 8), ('FONT', (0,0), (0,-1), 'Helvetica-Bold', 8), ('FONT', (0,0), (-1,0), 'Helvetica-Bold', 8), ('FONT', (0,-1), (-1,-1), 'Helvetica-Bold', 8), ('FONT', (-1,0), (-1,-1), 'Helvetica-Bold', 8), ('ALIGN', (1,1), (-1,-1), 'RIGHT'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('LINEBELOW', (0,-1), (-1,-1), 0.25, colors.black), ('LINEAFTER', (-1,0), (-1,-1), 0.25, colors.black), ('LINEBEFORE', (-1,0), (-1,-1), 1.0, colors.black), ('LINEABOVE', (0,-1), (-1,-1), 1.0, colors.black), #('LINEABOVE', (0,0), (-1,0), 0.25, colors.black), ] @implementer(IContractStatisticsReport) class ContractStatisticsReport(Report): data = None def __init__(self, author='System'): super(ContractStatisticsReport, self).__init__( args=[], kwargs={'author':author}) self.author = author self.creation_dt_string = self.creation_dt.astimezone( getUtility(IIkobaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z") self.data = get_contract_stats() def create_pdf(self): portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE creator = getUtility(IPDFCreator, name='landscape') table_data = tbl_data_to_table(*self.data) col_widths = [None,] + [1.6*cm] * len(self.data[1]) + [None,] pdf_data = [Paragraph('%s' % self.creation_dt_string, STYLE["Normal"]), Spacer(1, 12),] pdf_data += [ Table(table_data, style=TABLE_STYLE, colWidths=col_widths)] doc_title = translate(_('Contracts'), 'waeup.ikoba', target_language=portal_language) footer_title = doc_title pdf = creator.create_pdf( pdf_data, None, doc_title, self.author, footer_title ) return pdf @implementer(IReportGenerator) class ContractStatisticsReportGenerator(grok.GlobalUtility): title = _('Contract Statistics') grok.name('contract_stats') def generate(self, site, author=None): result = ContractStatisticsReport( author=author) return result ############################################################### ## Browser related stuff ## ## XXX: move to local browser module ############################################################### from waeup.ikoba.browser.layout import IkobaPage from waeup.ikoba.reports import get_generators from waeup.ikoba.browser.breadcrumbs import Breadcrumb grok.templatedir('browser_templates') class ContractStatisticsReportGeneratorPage(IkobaPage): grok.context(ContractStatisticsReportGenerator) grok.name('index.html') grok.require('waeup.manageReports') label = _('Create contract statistics report') @property def generator_name(self): for name, gen in get_generators(): if gen == self.context: return name return None def update(self, CREATE=None): self.parent_url = self.url(self.context.__parent__) if CREATE: # create a new report job for contracts container = self.context.__parent__ user_id = self.request.principal.id kw = dict() self.flash(_('New report is being created in background')) job_id = container.start_report_job( self.generator_name, user_id, kw=kw) ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','') grok.getSite().logger.info( '%s - report %s created: %s' % ( ob_class, job_id, self.context.title)) self.redirect(self.parent_url) return return class ContractStatisticsReportPDFView(grok.View): grok.context(IContractStatisticsReport) grok.name('pdf') grok.require('waeup.Public') prefix = '' def _filename(self): return 'ContractStatisticsReport.pdf' def render(self): filename = self._filename().replace( '/', '_').replace(' ','_').replace(':', '-') self.response.setHeader( 'Content-Type', 'application/pdf') self.response.setHeader( 'Content-Disposition:', 'attachment; filename="%s' % filename) pdf_stream = self.context.create_pdf() ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','') grok.getSite().logger.info('%s - report %s downloaded: %s' % ( ob_class, self.context.__name__, filename)) return pdf_stream class ContractStatsBreadcrumb(Breadcrumb): """A breadcrumb for reports. """ grok.context(ContractStatisticsReportGenerator) title = _(u'Contract Statistics') target = None