Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traceback in Statement view #743

Merged
merged 17 commits into from
Apr 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Changelog

**Fixed**

- #743 Traceback when accessing the view of a Statement
- #734 Chameleon parse error in "Analyses performed and published as % of total", "Analyses summary per department" and "Data entry day book" productivity reports
- #750 Wrong redirect after Batch Label edit or creation
- #721 Fix filter functionality of Worksheets after sort/pagination
Expand Down
183 changes: 103 additions & 80 deletions bika/lims/browser/invoicebatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,82 @@
# 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
from bika.lims.utils import currency_format, get_link, get_email_link
import csv
from cStringIO import StringIO


class InvoiceBatchInvoicesView(BikaListingView):

def __init__(self, context, request):
super(InvoiceBatchInvoicesView, self).__init__(context, request)
self.contentFilter = {}
self.contentFilter = {
'portal_type': 'Invoice',
'path': {
"query": "/".join(self.context.getPhysicalPath()),
"level": 0
},
}
self.title = context.Title()
self.description = ""
self.show_sort_column = False
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 = {}
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',
'contentFilter': {},
'contentFilter': self.contentFilter,
'title': _('Default'),
'transitions': [],
'columns': [
Expand All @@ -68,56 +98,39 @@ 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):
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')
self.show_all = True
self.contentsMethod = self.getInvoices
items = BikaListingView.folderitems(self, full_objects)
for item in items:
obj = item['obj']
number_link = "<a href='%s'>%s</a>" % (
item['url'], obj.getId()
)
item['replace']['id'] = number_link

if obj.getClient():
item['client'] = obj.getClient().Title()
item['replace']['client'] = "<a href='%s'>%s</a>" % (
obj.getClient().absolute_url(), obj.getClient().Title()
)

item['email'] = obj.getClient().getEmailAddress()
item['replace']['email'] = "<a href='%s'>%s</a>" % (
'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
item['replace']['id'] = get_link(api.get_url(obj), obj.getId())
client = obj.getClient()
if client:
item['client'] = client.Title()
item['replace']['client'] = get_link(client.absolute_url(), item['client'])
item['email'] = client.getEmailAddress()
item['replace']['email'] = get_email_link(client.getEmailAddress())
item['phone'] = client.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 item


class BatchFolderExportCSV(InvoiceBatchInvoicesView):
Expand All @@ -129,15 +142,18 @@ def __call__(self, REQUEST, RESPONSE):
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
invoices = self.getInvoices({})
# 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
invoices = map(api.get_object, api.search(self.contentFilter, 'portal_catalog'))
if not len(invoices):
container.plone_log("InvoiceBatch contains no entries")

Expand Down Expand Up @@ -195,8 +211,15 @@ def __call__(self, REQUEST, RESPONSE):
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)
setheader(
'Content-Length',
len(result)
)
setheader(
'Content-Type',
'text/x-comma-separated-values'
)
setheader(
'Content-Disposition',
'inline; filename=%s' % filename)
RESPONSE.write(result)
31 changes: 21 additions & 10 deletions bika/lims/content/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -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', ),
Expand All @@ -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,
Expand Down Expand Up @@ -157,4 +167,5 @@ def current_date(self):
""" return current date """
return DateTime()


registerType(Invoice, PROJECTNAME)