From 2b1b82f9fa18ddc3d888b2bc05d862528567f675 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Wed, 21 Mar 2018 11:41:30 +0100 Subject: [PATCH 01/14] Apply PEP8 style guidelines --- bika/lims/browser/invoicebatch.py | 83 ++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index 86a91e71bb..a3b076cb39 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -26,27 +26,47 @@ def __init__(self, context, request): request.set('disable_border', 1) self.context_actions = {} self.columns = { - 'id': {'title': _('Invoice Number'), - 'toggle': True }, - 'client': {'title': _('Client'), - 'toggle': True}, - 'email': {'title': _('Email Address'), - 'toggle': False}, - 'phone': {'title': _('Phone'), - 'toggle': False}, - 'invoicedate': {'title': _('Invoice Date'), - 'toggle': True}, - 'startdate': {'title': _('Start Date'), - 'toggle': False}, - 'enddate': {'title': _('End Date'), - 'toggle': False}, - 'subtotal': {'title': _('Subtotal'), - 'toggle': False}, - 'vatamount': {'title': _('VAT'), - 'toggle': False}, - 'total': {'title': _('Total'), - 'toggle': True}, - } + 'id': { + 'title': _('Invoice Number'), + 'toggle': True + }, + 'client': { + 'title': _('Client'), + 'toggle': True + }, + 'email': { + 'title': _('Email Address'), + 'toggle': False + }, + 'phone': { + 'title': _('Phone'), + 'toggle': False + }, + 'invoicedate': { + 'title': _('Invoice Date'), + 'toggle': True + }, + 'startdate': { + 'title': _('Start Date'), + 'toggle': False + }, + 'enddate': { + 'title': _('End Date'), + 'toggle': False + }, + 'subtotal': { + 'title': _('Subtotal'), + 'toggle': False + }, + 'vatamount': { + 'title': _('VAT'), + 'toggle': False + }, + 'total': { + 'title': _('Total'), + 'toggle': True + }, + } self.review_states = [ { 'id': 'default', @@ -122,7 +142,7 @@ def folderitems(self, full_objects=False): class BatchFolderExportCSV(InvoiceBatchInvoicesView): - def __call__(self, REQUEST, RESPONSE): + def __call__(self, request, response): """ Export invoice batch into csv format. Writes the csv file into the RESPONSE to allow @@ -194,9 +214,16 @@ def __call__(self, REQUEST, RESPONSE): result = ramdisk.getvalue() ramdisk.close() # stream file to browser - setheader = RESPONSE.setHeader - setheader('Content-Length', len(result)) - setheader('Content-Type', - 'text/x-comma-separated-values') - setheader('Content-Disposition', 'inline; filename=%s' % filename) - RESPONSE.write(result) + setheader = response.setHeader + setheader( + 'Content-Length', + len(result) + ) + setheader( + 'Content-Type', + 'text/x-comma-separated-values' + ) + setheader( + 'Content-Disposition', + 'inline; filename=%s' % filename) + response.write(result) From 60d09097dcbb05ce7fb20d05fdbae9a80c764457 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Thu, 22 Mar 2018 12:27:45 +0100 Subject: [PATCH 02/14] Apply PEP8 style guidelines --- bika/lims/content/invoice.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/bika/lims/content/invoice.py b/bika/lims/content/invoice.py index bfed0e85b2..56a0fed167 100644 --- a/bika/lims/content/invoice.py +++ b/bika/lims/content/invoice.py @@ -22,32 +22,37 @@ import sys schema = BikaSchema.copy() + Schema(( - ReferenceField('Client', + ReferenceField( + 'Client', required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=('Client',), relationship='ClientInvoice', ), - ReferenceField('AnalysisRequest', + ReferenceField( + 'AnalysisRequest', required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=('AnalysisRequest',), relationship='AnalysisRequestInvoice', ), - ReferenceField('SupplyOrder', + ReferenceField( + 'SupplyOrder', required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=('SupplyOrder',), relationship='SupplyOrderInvoice', ), - DateTimeField('InvoiceDate', + DateTimeField( + 'InvoiceDate', required=1, default_method='current_date', widget=DateTimeWidget( label=_("Date"), ), ), - TextField('Remarks', + TextField( + 'Remarks', searchable=True, default_content_type='text/plain', allowed_content_types=('text/plain', ), @@ -58,34 +63,39 @@ append_only=True, ), ), - ComputedField('Subtotal', + ComputedField( + 'Subtotal', expression='context.getSubtotal()', widget=ComputedWidget( label=_("Subtotal"), visible=False, ), ), - ComputedField('VATAmount', + ComputedField( + 'VATAmount', expression='context.getVATAmount()', widget=ComputedWidget( label=_("VAT Total"), visible=False, ), ), - ComputedField('Total', + ComputedField( + 'Total', expression='context.getTotal()', widget=ComputedWidget( label=_("Total"), visible=False, ), ), - ComputedField('ClientUID', + ComputedField( + 'ClientUID', expression='here.getClient() and here.getClient().UID()', widget=ComputedWidget( visible=False, ), ), - ComputedField('InvoiceSearchableText', + ComputedField( + 'InvoiceSearchableText', expression='here.getInvoiceSearchableText()', widget=ComputedWidget( visible=False, @@ -157,4 +167,5 @@ def current_date(self): """ return current date """ return DateTime() + registerType(Invoice, PROJECTNAME) From 71034264a2c93fb8869e301a2be125575da48b7e Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Thu, 22 Mar 2018 13:26:41 +0100 Subject: [PATCH 03/14] Remove getInvoices deprecated method --- bika/lims/browser/invoicebatch.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index a3b076cb39..23024845d6 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -88,25 +88,9 @@ def __init__(self, context, request): }, ] - def getInvoices(self, contentFilter): - return self.context.objectValues('Invoice') - - # def __call__(self): - # mtool = getToolByName(self.context, 'portal_membership') - # addPortalMessage = self.context.plone_utils.addPortalMessage - # if mtool.checkPermission(AddInvoice, self.context): - # clients = self.context.clients.objectIds() - # if clients: - # self.context_actions[_('Add')] = { - # 'url': 'createObject?type_name=Invoice', - # 'icon': '++resource++bika.lims.images/add.png' - # } - # return super(InvoiceBatchInvoicesView, self).__call__() - def folderitems(self, full_objects=False): currency = currency_format(self.context, 'en') self.show_all = True - self.contentsMethod = self.getInvoices items = BikaListingView.folderitems(self, full_objects) for item in items: obj = item['obj'] @@ -157,7 +141,7 @@ def __call__(self, request, response): assert container container.plone_log("Exporting InvoiceBatch to CSV format for PASTEL") # Getting the invoice batch's invoices - invoices = self.getInvoices({}) + # TODO -> get batch invoices if not len(invoices): container.plone_log("InvoiceBatch contains no entries") From f0d5b8b34978d2c771842b38e9f919d34b350bea Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Thu, 22 Mar 2018 13:29:11 +0100 Subject: [PATCH 04/14] Update how invoices are obtained --- bika/lims/browser/invoicebatch.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index 23024845d6..bb17bcbd15 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -15,7 +15,9 @@ class InvoiceBatchInvoicesView(BikaListingView): def __init__(self, context, request): super(InvoiceBatchInvoicesView, self).__init__(context, request) - self.contentFilter = {} + self.contentFilter['path'] = { + "query": "/".join(self.context.getPhysicalPath()), + "level": 0} self.title = context.Title() self.description = "" self.show_sort_column = False @@ -70,7 +72,7 @@ def __init__(self, context, request): self.review_states = [ { 'id': 'default', - 'contentFilter': {}, + 'contentFilter': self.contentFilter, 'title': _('Default'), 'transitions': [], 'columns': [ From 75cf1c2050e65f6904dbce8ff9a2b51f20a23f20 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Thu, 22 Mar 2018 13:35:00 +0100 Subject: [PATCH 05/14] Update contentFilter to include portal type --- bika/lims/browser/invoicebatch.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index bb17bcbd15..fb9bfd58ab 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -15,9 +15,13 @@ class InvoiceBatchInvoicesView(BikaListingView): def __init__(self, context, request): super(InvoiceBatchInvoicesView, self).__init__(context, request) - self.contentFilter['path'] = { - "query": "/".join(self.context.getPhysicalPath()), - "level": 0} + self.content_filter = { + 'portal_type': 'Invoice', + 'path': { + "query": "/".join(self.context.getPhysicalPath()), + "level": 0 + }, + } self.title = context.Title() self.description = "" self.show_sort_column = False From 0a741513e3ab90c34d3d14bf4af605e71e59fa0b Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Thu, 22 Mar 2018 13:36:08 +0100 Subject: [PATCH 06/14] Move attribute definition to class init --- bika/lims/browser/invoicebatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index fb9bfd58ab..edb87ca3ab 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -28,6 +28,7 @@ def __init__(self, context, request): self.show_select_row = False self.show_select_all_checkbox = False self.show_select_column = True + self.show_all = True self.pagesize = 25 request.set('disable_border', 1) self.context_actions = {} @@ -96,7 +97,6 @@ def __init__(self, context, request): def folderitems(self, full_objects=False): currency = currency_format(self.context, 'en') - self.show_all = True items = BikaListingView.folderitems(self, full_objects) for item in items: obj = item['obj'] From 6067c01bc036187f533a7634df1db3d5bc06e141 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Thu, 22 Mar 2018 14:12:00 +0100 Subject: [PATCH 07/14] Update invoice's data via folderitem and correct typo --- bika/lims/browser/invoicebatch.py | 68 +++++++++++++++++-------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index edb87ca3ab..7a168f0527 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -15,7 +15,7 @@ class InvoiceBatchInvoicesView(BikaListingView): def __init__(self, context, request): super(InvoiceBatchInvoicesView, self).__init__(context, request) - self.content_filter = { + self.contentFilter = { 'portal_type': 'Invoice', 'path': { "query": "/".join(self.context.getPhysicalPath()), @@ -95,39 +95,45 @@ def __init__(self, context, request): }, ] - def folderitems(self, full_objects=False): + def folderitem(self, obj, item, idx): + """ + Replace or add the required/wanted fields for each invoice + in the item dictionary + + :param obj: the instance of the class to be foldered. In our case, an + Invoice + :param item: dict containing the properties of the object to be used by + the template + :return: dictionary with the updated fields of the invoice being processed + """ currency = currency_format(self.context, 'en') - items = BikaListingView.folderitems(self, full_objects) - for item in items: - obj = item['obj'] - number_link = "%s" % ( - item['url'], obj.getId() + number_link = "%s" % ( + item['url'], obj.getId() + ) + item['replace']['id'] = number_link + if obj.getClient(): + item['client'] = obj.getClient().Title() + item['replace']['client'] = "%s" % ( + obj.getClient().absolute_url(), item['client'] + ) + item['email'] = obj.getClient().getEmailAddress() + item['replace']['email'] = "%s" % ( + 'mailto:%s' % obj.getClient().getEmailAddress(), obj.getClient().getEmailAddress() ) - item['replace']['id'] = number_link - - if obj.getClient(): - item['client'] = obj.getClient().Title() - item['replace']['client'] = "%s" % ( - obj.getClient().absolute_url(), obj.getClient().Title() - ) + item['phone'] = obj.getClient().getPhone() + else: + item['client'] = '' + item['email'] = '' + item['phone'] = '' + + item['invoicedate'] = self.ulocalized_time(obj.getInvoiceDate()) + item['startdate'] = self.ulocalized_time(obj.getBatchStartDate()) + item['enddate'] = self.ulocalized_time(obj.getBatchEndDate()) + item['subtotal'] = currency(obj.getSubtotal()) + item['vatamount'] = currency(obj.getVATAmount()) + item['total'] = currency(obj.getTotal()) - item['email'] = obj.getClient().getEmailAddress() - item['replace']['email'] = "%s" % ( - 'mailto:%s' % obj.getClient().getEmailAddress(), obj.getClient().getEmailAddress() - ) - item['phone'] = obj.getClient().getPhone() - else: - item['client'] = '' - item['email'] = '' - item['phone'] = '' - - item['invoicedate'] = self.ulocalized_time(obj.getInvoiceDate()) - item['startdate'] = self.ulocalized_time(obj.getBatchStartDate()) - item['enddate'] = self.ulocalized_time(obj.getBatchEndDate()) - item['subtotal'] = currency(obj.getSubtotal()) - item['vatamount'] = currency(obj.getVATAmount()) - item['total'] = currency(obj.getTotal()) - return items + return item class BatchFolderExportCSV(InvoiceBatchInvoicesView): From 7aa9fedbee6f2a768f8ce400f8379bc7548e9d77 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Fri, 23 Mar 2018 10:58:32 +0100 Subject: [PATCH 08/14] Fix invoice batch CSV export by updating how invoices are obtained --- bika/lims/browser/invoicebatch.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index 7a168f0527..cc144f4b42 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -5,12 +5,15 @@ # Copyright 2018 by it's authors. # Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst. +from senaite import api + from bika.lims.browser.bika_listing import BikaListingView from bika.lims import bikaMessageFactory as _ from bika.lims.utils import currency_format import csv from cStringIO import StringIO + class InvoiceBatchInvoicesView(BikaListingView): def __init__(self, context, request): @@ -138,22 +141,26 @@ def folderitem(self, obj, item, idx): class BatchFolderExportCSV(InvoiceBatchInvoicesView): - def __call__(self, request, response): + def __call__(self, REQUEST, RESPONSE): """ Export invoice batch into csv format. Writes the csv file into the RESPONSE to allow the file to be streamed to the user. Nothing gets returned. """ - delimiter = ',' filename = 'invoice_batch.txt' # Getting the invoice batch container = self.context assert container container.plone_log("Exporting InvoiceBatch to CSV format for PASTEL") - # Getting the invoice batch's invoices - # TODO -> get batch invoices + # Getting the invoice batch's invoices: + # Since BatchFolderExportCSV does not provide an initializer method + # (__init__) then the base class initializer is called automatically + # and we can use the already defined contentFilter to retrieve the + # invoice batch invoices + portal_catalog = api.get_tool('portal_catalog') + invoices = map(api.get_object, portal_catalog(self.contentFilter)) if not len(invoices): container.plone_log("InvoiceBatch contains no entries") @@ -210,7 +217,7 @@ def __call__(self, request, response): result = ramdisk.getvalue() ramdisk.close() # stream file to browser - setheader = response.setHeader + setheader = RESPONSE.setHeader setheader( 'Content-Length', len(result) @@ -222,4 +229,4 @@ def __call__(self, request, response): setheader( 'Content-Disposition', 'inline; filename=%s' % filename) - response.write(result) + RESPONSE.write(result) From 6d12f50da19b439367d98233aa2b082829e7f968 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Fri, 23 Mar 2018 11:05:04 +0100 Subject: [PATCH 09/14] Update CHANGES.rst --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index da08bab21f..31437a02f6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -22,6 +22,7 @@ Changelog **Fixed** +- #743 Traceback when accessing the view of a Statement - #721 Fix filter functionality of Worksheets after sort/pagination - #738 Traceback when Invalidating Analysis Requests - #694 Bad calculation of min and max in ReferenceResults on negative result From 14b29590afa56bd11b9b047574925ac461a92b8b Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Fri, 23 Mar 2018 11:14:11 +0100 Subject: [PATCH 10/14] use api search function to query for invoices --- bika/lims/browser/invoicebatch.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index cc144f4b42..f64a66aa2f 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -159,8 +159,7 @@ def __call__(self, REQUEST, RESPONSE): # (__init__) then the base class initializer is called automatically # and we can use the already defined contentFilter to retrieve the # invoice batch invoices - portal_catalog = api.get_tool('portal_catalog') - invoices = map(api.get_object, portal_catalog(self.contentFilter)) + invoices = map(api.get_object, api.search(self.contentFilter, 'portal_catalog')) if not len(invoices): container.plone_log("InvoiceBatch contains no entries") From bb9da383211ae6e2fc9507587dee9d77594b4062 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Tue, 3 Apr 2018 10:45:13 +0200 Subject: [PATCH 11/14] Use utils function get_link to get id link --- bika/lims/browser/invoicebatch.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index f64a66aa2f..dfabd03536 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -9,7 +9,7 @@ from bika.lims.browser.bika_listing import BikaListingView from bika.lims import bikaMessageFactory as _ -from bika.lims.utils import currency_format +from bika.lims.utils import currency_format, get_link import csv from cStringIO import StringIO @@ -110,10 +110,7 @@ def folderitem(self, obj, item, idx): :return: dictionary with the updated fields of the invoice being processed """ currency = currency_format(self.context, 'en') - number_link = "%s" % ( - item['url'], obj.getId() - ) - item['replace']['id'] = number_link + item['replace']['id'] = get_link(api.get_url(obj), obj.getId()) if obj.getClient(): item['client'] = obj.getClient().Title() item['replace']['client'] = "%s" % ( From 50cbddb58018779e6e0d121eaea00977e721598c Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Tue, 3 Apr 2018 10:47:40 +0200 Subject: [PATCH 12/14] Store client in a variable Since we are using the client object in several places it is better to store it in a local variable and use it when the client is needed. --- bika/lims/browser/invoicebatch.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index dfabd03536..667c2c6473 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -111,16 +111,17 @@ def folderitem(self, obj, item, idx): """ currency = currency_format(self.context, 'en') item['replace']['id'] = get_link(api.get_url(obj), obj.getId()) - if obj.getClient(): - item['client'] = obj.getClient().Title() + client = obj.getClient() + if client: + item['client'] = client.Title() item['replace']['client'] = "%s" % ( - obj.getClient().absolute_url(), item['client'] + client.absolute_url(), item['client'] ) - item['email'] = obj.getClient().getEmailAddress() + item['email'] = client.getEmailAddress() item['replace']['email'] = "%s" % ( - 'mailto:%s' % obj.getClient().getEmailAddress(), obj.getClient().getEmailAddress() + 'mailto:%s' % client.getEmailAddress(), client.getEmailAddress() ) - item['phone'] = obj.getClient().getPhone() + item['phone'] = client.getPhone() else: item['client'] = '' item['email'] = '' From 10a340ab5ed7783796d18d6c07d00543de1b2bf6 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Tue, 3 Apr 2018 10:54:21 +0200 Subject: [PATCH 13/14] Use get_link to get urls --- bika/lims/browser/invoicebatch.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index 667c2c6473..581840e506 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -114,13 +114,10 @@ def folderitem(self, obj, item, idx): client = obj.getClient() if client: item['client'] = client.Title() - item['replace']['client'] = "%s" % ( - client.absolute_url(), item['client'] - ) + item['replace']['client'] = get_link(client.absolute_url(), item['client']) item['email'] = client.getEmailAddress() - item['replace']['email'] = "%s" % ( - 'mailto:%s' % client.getEmailAddress(), client.getEmailAddress() - ) + item['replace']['email'] = get_link('mailto:%s' % client.getEmailAddress(), + client.getEmailAddress()) item['phone'] = client.getPhone() else: item['client'] = '' From 1527b7785f5126c33932efd0e3e95e4bd997bec0 Mon Sep 17 00:00:00 2001 From: Juan Gallostra Date: Tue, 3 Apr 2018 10:56:26 +0200 Subject: [PATCH 14/14] Use get_email_link to obtain the client's email --- bika/lims/browser/invoicebatch.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bika/lims/browser/invoicebatch.py b/bika/lims/browser/invoicebatch.py index 581840e506..86b9e8c916 100644 --- a/bika/lims/browser/invoicebatch.py +++ b/bika/lims/browser/invoicebatch.py @@ -9,7 +9,7 @@ from bika.lims.browser.bika_listing import BikaListingView from bika.lims import bikaMessageFactory as _ -from bika.lims.utils import currency_format, get_link +from bika.lims.utils import currency_format, get_link, get_email_link import csv from cStringIO import StringIO @@ -116,8 +116,7 @@ def folderitem(self, obj, item, idx): item['client'] = client.Title() item['replace']['client'] = get_link(client.absolute_url(), item['client']) item['email'] = client.getEmailAddress() - item['replace']['email'] = get_link('mailto:%s' % client.getEmailAddress(), - client.getEmailAddress()) + item['replace']['email'] = get_email_link(client.getEmailAddress()) item['phone'] = client.getPhone() else: item['client'] = ''