From 4247cd83e58fa2504c441511cff090e1fc6b5649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 21 Feb 2020 21:47:39 +0100 Subject: [PATCH 1/5] Generate pdf and email when rejection on Add Sample --- .../browser/analysisrequest/reject_samples.py | 15 +- bika/lims/utils/analysisrequest.py | 194 ++++++++++-------- bika/lims/workflow/analysisrequest/events.py | 4 + 3 files changed, 117 insertions(+), 96 deletions(-) diff --git a/bika/lims/browser/analysisrequest/reject_samples.py b/bika/lims/browser/analysisrequest/reject_samples.py index 4f1d13a9e0..96ab0f95cc 100644 --- a/bika/lims/browser/analysisrequest/reject_samples.py +++ b/bika/lims/browser/analysisrequest/reject_samples.py @@ -26,9 +26,10 @@ from bika.lims.browser import BrowserView, ulocalized_time from bika.lims.catalog.analysisrequest_catalog import \ CATALOG_ANALYSIS_REQUEST_LISTING -from bika.lims.utils.analysisrequest import notify_rejection from plone.memoize import view +from bika.lims.utils.analysisrequest import do_rejection + class RejectSamplesView(BrowserView): """View that renders the Samples rejection view @@ -97,14 +98,14 @@ def __call__(self): obj = api.get_object_by_uid(sample_uid) rejection_reasons = { "other": other, - "selected": reasons } + "selected": reasons + } obj.setRejectionReasons([rejection_reasons]) - wf.doActionFor(obj, "reject") - processed.append(obj) - # Client needs to be notified? - if sample.get("notify", "") == "on": - notify_rejection(obj) + # Reject the sample + notify = sample.get("notify", "") == "on" + do_rejection(obj, notify=notify) + processed.append(obj) if not processed: return self.redirect(message=_("No samples were rejected")) diff --git a/bika/lims/utils/analysisrequest.py b/bika/lims/utils/analysisrequest.py index b5edb98158..34c5069380 100644 --- a/bika/lims/utils/analysisrequest.py +++ b/bika/lims/utils/analysisrequest.py @@ -18,24 +18,26 @@ # Copyright 2018-2020 by it's authors. # Some rights reserved, see README and LICENSE. -import six import itertools -import os -import tempfile from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText +import six from Products.Archetypes.config import UID_CATALOG from Products.CMFCore.utils import getToolByName from Products.CMFPlone.utils import _createObjectByType from Products.CMFPlone.utils import safe_unicode -from email.Utils import formataddr from zope.interface import alsoProvides from zope.lifecycleevent import modified from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims import logger +from bika.lims.api.mail import is_valid_email_address +from bika.lims.api.mail import send_email +from bika.lims.api.mail import to_email_address +from bika.lims.api.mail import to_email_attachment +from bika.lims.api.mail import to_email_body_text +from bika.lims.api.mail import to_email_subject from bika.lims.catalog import SETUP_CATALOG from bika.lims.idserver import renameAfterCreation from bika.lims.interfaces import IAnalysisRequest @@ -44,13 +46,10 @@ from bika.lims.interfaces import IAnalysisService from bika.lims.interfaces import IReceived from bika.lims.interfaces import IRoutineAnalysis -from bika.lims.utils import attachPdf from bika.lims.utils import changeWorkflowState from bika.lims.utils import copy_field_values from bika.lims.utils import createPdf -from bika.lims.utils import encode_header from bika.lims.utils import tmpID -from bika.lims.utils import to_utf8 from bika.lims.workflow import ActionHandlerPool from bika.lims.workflow import doActionFor from bika.lims.workflow import push_reindex_to_actions_pool @@ -134,7 +133,7 @@ def create_analysisrequest(client, request, values, analyses=None, # If rejection reasons have been set, reject automatically if rejection_reasons: - doActionFor(ar, "reject") + do_rejection(ar) # In "received" state already return ar @@ -146,7 +145,7 @@ def create_analysisrequest(client, request, values, analyses=None, # If rejection reasons have been set, reject the sample automatically if rejection_reasons: - doActionFor(ar, "reject") + do_rejection(ar) return ar @@ -261,85 +260,6 @@ def to_service_uid(uid_brain_obj_str): return None -def notify_rejection(analysisrequest): - """ - Notifies via email that a given Analysis Request has been rejected. The - notification is sent to the Client contacts assigned to the Analysis - Request. - - :param analysisrequest: Analysis Request to which the notification refers - :returns: true if success - """ - - # We do this imports here to avoid circular dependencies until we deal - # better with this notify_rejection thing. - from bika.lims.browser.analysisrequest.reject import \ - AnalysisRequestRejectPdfView, AnalysisRequestRejectEmailView - - arid = analysisrequest.getId() - - # This is the template to render for the pdf that will be either attached - # to the email and attached the the Analysis Request for further access - tpl = AnalysisRequestRejectPdfView(analysisrequest, analysisrequest.REQUEST) - html = tpl.template() - html = safe_unicode(html).encode('utf-8') - filename = '%s-rejected' % arid - pdf_fn = tempfile.mktemp(suffix=".pdf") - pdf = createPdf(htmlreport=html, outfile=pdf_fn) - if pdf: - # Attach the pdf to the Analysis Request - attid = analysisrequest.aq_parent.generateUniqueId('Attachment') - att = _createObjectByType( - "Attachment", analysisrequest.aq_parent, attid) - att.setAttachmentFile(open(pdf_fn)) - # Awkward workaround to rename the file - attf = att.getAttachmentFile() - attf.filename = '%s.pdf' % filename - att.setAttachmentFile(attf) - att.unmarkCreationFlag() - renameAfterCreation(att) - analysisrequest.addAttachment(att) - os.remove(pdf_fn) - - # This is the message for the email's body - tpl = AnalysisRequestRejectEmailView( - analysisrequest, analysisrequest.REQUEST) - html = tpl.template() - html = safe_unicode(html).encode('utf-8') - - # compose and send email. - mailto = [] - lab = analysisrequest.bika_setup.laboratory - mailfrom = formataddr((encode_header(lab.getName()), lab.getEmailAddress())) - mailsubject = _('%s has been rejected') % arid - contacts = [analysisrequest.getContact()] + analysisrequest.getCCContact() - for contact in contacts: - name = to_utf8(contact.getFullname()) - email = to_utf8(contact.getEmailAddress()) - if email: - mailto.append(formataddr((encode_header(name), email))) - if not mailto: - return False - mime_msg = MIMEMultipart('related') - mime_msg['Subject'] = mailsubject - mime_msg['From'] = mailfrom - mime_msg['To'] = ','.join(mailto) - mime_msg.preamble = 'This is a multi-part MIME message.' - msg_txt = MIMEText(html, _subtype='html') - mime_msg.attach(msg_txt) - if pdf: - attachPdf(mime_msg, pdf, filename) - - try: - host = getToolByName(analysisrequest, 'MailHost') - host.send(mime_msg.as_string(), immediate=True) - except: - logger.warning( - "Email with subject %s was not sent (SMTP connection error)" % mailsubject) - - return True - - def create_retest(ar): """Creates a retest (Analysis Request) from an invalidated Analysis Request :param ar: The invalidated Analysis Request @@ -549,3 +469,99 @@ def resolve_rejection_reasons(values): return [{"selected": selected, "other": other}] return [] + + +def do_rejection(sample, notify=None): + """Rejects the sample and if succeeds, generates the rejection pdf and + sends a notification email. If notify is None, the notification email will + only be sent if the setting in Setup is enabled + """ + sample_id = api.get_id(sample) + if not sample.getRejectionReasons(): + logger.warn("Cannot reject {} w/o rejection reasons".format(sample_id)) + return + + success, msg = doActionFor(sample, "reject") + if not success: + logger.warn("Cannot reject the sample {}".format(sample_id)) + return + + # Generate a pdf with the rejection reasons + pdf = get_rejection_pdf(sample) + + # Attach the PDF to the sample + filename = "{}-rejected.pdf".format(sample_id) + sample.createAttachment(pdf, filename=filename) + + # Do we need to send a notification email? + if notify is None: + setup = api.get_setup() + notify = setup.getNotifyOnSampleRejection() + + if notify: + # Compose the email + mime_msg = get_rejection_mail(sample) + # Attach the pdf + mime_msg.attach(to_email_attachment(pdf)) + # Send the email + send_email(mime_msg) + + +def get_rejection_pdf(sample): + """Generates a pdf with sample rejection reasons + """ + # Avoid circular dependencies + from bika.lims.browser.analysisrequest.reject import \ + AnalysisRequestRejectPdfView + + # Render the html's rejection document + tpl = AnalysisRequestRejectPdfView(sample, api.get_request()) + html = tpl.template() + html = safe_unicode(html).encode("utf-8") + + # Generate the pdf + return createPdf(htmlreport=html) + + +def get_rejection_mail(sample): + """Generates an email to sample contacts with rejection reasons + """ + # Avoid circular dependencies + from bika.lims.browser.analysisrequest.reject import \ + AnalysisRequestRejectEmailView + + # Render the email body + tpl = AnalysisRequestRejectEmailView(sample, api.get_request()) + email_body = tpl.template() + + def to_valid_email_address(contact): + if not contact: + return None + address = contact.getEmailAddress() + if not is_valid_email_address(address): + return None + name = contact.getFullname() or "" + return to_email_address(address, name=name) + + # Get the recipients + _to = [sample.getContact()] + sample.getCCContact() + _to = map(to_valid_email_address, _to) + _to = filter(None, _to) + + # Compose the email + lab = api.get_setup().laboratory + _from = to_email_address(lab.getEmailAddress(), lab.getName()) + _subject = _("%s has been rejected") % api.get_id(sample) + _subject = to_email_subject(_subject) + _body = to_email_body_text(email_body) + + # Create the enclosing message + _preamble = "This is a multi-part message in MIME format.\n" + mime_msg = MIMEMultipart() + mime_msg.preamble = _preamble + mime_msg["Subject"] = _subject + mime_msg["From"] = _from + mime_msg["To"] = ", ".join(_to) + mime_msg.attach(_body) + return mime_msg + diff --git a/bika/lims/workflow/analysisrequest/events.py b/bika/lims/workflow/analysisrequest/events.py index 8cbcdf4938..8d454623d3 100644 --- a/bika/lims/workflow/analysisrequest/events.py +++ b/bika/lims/workflow/analysisrequest/events.py @@ -19,12 +19,16 @@ # Some rights reserved, see README and LICENSE. from bika.lims import api +from bika.lims.api.mail import send_email +from bika.lims.api.mail import to_email_attachment from bika.lims.interfaces import IAnalysisRequestPartition from bika.lims.interfaces import IDetachedPartition from bika.lims.interfaces import IReceived from bika.lims.interfaces import IVerified from bika.lims.utils import changeWorkflowState from bika.lims.utils.analysisrequest import create_retest +from bika.lims.utils.analysisrequest import get_rejection_mail +from bika.lims.utils.analysisrequest import get_rejection_pdf from bika.lims.workflow import doActionFor as do_action_for from bika.lims.workflow import get_prev_status_from_history from bika.lims.workflow.analysisrequest import AR_WORKFLOW_ID From e65c075a87b50a2e0d59c00f94a1df4696faa8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 21 Feb 2020 21:49:56 +0100 Subject: [PATCH 2/5] Changelog --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 36f6409034..8925b6f1dc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -59,6 +59,7 @@ Changelog **Fixed** +- #1552 Rejection on registration is neither generating rejection pdf nor email - #1550 Fix Uncaught TypeError in combogrid - #1542 Fix sporadical errors when contacts do not have a valid email address - #1540 Fix flushing CCEmail fields in Sample Add Form From aa28cc83faef9a91aa6f7ae0e9df7d16cb157394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 21 Feb 2020 22:52:58 +0100 Subject: [PATCH 3/5] Use the mail api to compose the rejection email --- bika/lims/api/mail.py | 9 +++-- bika/lims/utils/analysisrequest.py | 41 +++++++------------- bika/lims/workflow/analysisrequest/events.py | 2 - 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/bika/lims/api/mail.py b/bika/lims/api/mail.py index 88aa64dcac..c57d15e0be 100644 --- a/bika/lims/api/mail.py +++ b/bika/lims/api/mail.py @@ -21,6 +21,7 @@ import mimetypes import os import re +import six import socket from email import encoders from email.header import Header @@ -176,7 +177,7 @@ def compose_email(from_addr, to_addr, subj, body, attachments=[], **kw): """Compose a RFC 2822 MIME message :param from_address: Email from address - :param to_address: List of email or (name, email) pairs + :param to_address: An email or a list of emails :param subject: Email subject :param body: Email body :param attachments: List of email attachments @@ -184,7 +185,9 @@ def compose_email(from_addr, to_addr, subj, body, attachments=[], **kw): """ _preamble = "This is a multi-part message in MIME format.\n" _from = to_email_address(from_addr) - _to = to_email_address(to_addr) + if isinstance(to_addr, six.string_types): + to_addr = [to_addr] + _to = map(to_email_address, to_addr) _subject = to_email_subject(subj) _body = to_email_body_text(body, **kw) @@ -193,7 +196,7 @@ def compose_email(from_addr, to_addr, subj, body, attachments=[], **kw): mime_msg.preamble = _preamble mime_msg["Subject"] = _subject mime_msg["From"] = _from - mime_msg["To"] = _to + mime_msg["To"] = ", ".join(_to) mime_msg.attach(_body) # Attach attachments diff --git a/bika/lims/utils/analysisrequest.py b/bika/lims/utils/analysisrequest.py index 34c5069380..f31b1c1b9c 100644 --- a/bika/lims/utils/analysisrequest.py +++ b/bika/lims/utils/analysisrequest.py @@ -19,7 +19,6 @@ # Some rights reserved, see README and LICENSE. import itertools -from email.mime.multipart import MIMEMultipart import six from Products.Archetypes.config import UID_CATALOG @@ -32,12 +31,9 @@ from bika.lims import api from bika.lims import bikaMessageFactory as _ from bika.lims import logger +from bika.lims.api.mail import compose_email from bika.lims.api.mail import is_valid_email_address from bika.lims.api.mail import send_email -from bika.lims.api.mail import to_email_address -from bika.lims.api.mail import to_email_attachment -from bika.lims.api.mail import to_email_body_text -from bika.lims.api.mail import to_email_subject from bika.lims.catalog import SETUP_CATALOG from bika.lims.idserver import renameAfterCreation from bika.lims.interfaces import IAnalysisRequest @@ -499,10 +495,8 @@ def do_rejection(sample, notify=None): notify = setup.getNotifyOnSampleRejection() if notify: - # Compose the email - mime_msg = get_rejection_mail(sample) - # Attach the pdf - mime_msg.attach(to_email_attachment(pdf)) + # Compose and send the email + mime_msg = get_rejection_mail(sample, pdf) # Send the email send_email(mime_msg) @@ -523,7 +517,7 @@ def get_rejection_pdf(sample): return createPdf(htmlreport=html) -def get_rejection_mail(sample): +def get_rejection_mail(sample, rejection_pdf=None): """Generates an email to sample contacts with rejection reasons """ # Avoid circular dependencies @@ -540,28 +534,19 @@ def to_valid_email_address(contact): address = contact.getEmailAddress() if not is_valid_email_address(address): return None - name = contact.getFullname() or "" - return to_email_address(address, name=name) + return address # Get the recipients _to = [sample.getContact()] + sample.getCCContact() _to = map(to_valid_email_address, _to) _to = filter(None, _to) - # Compose the email lab = api.get_setup().laboratory - _from = to_email_address(lab.getEmailAddress(), lab.getName()) - _subject = _("%s has been rejected") % api.get_id(sample) - _subject = to_email_subject(_subject) - _body = to_email_body_text(email_body) - - # Create the enclosing message - _preamble = "This is a multi-part message in MIME format.\n" - mime_msg = MIMEMultipart() - mime_msg.preamble = _preamble - mime_msg["Subject"] = _subject - mime_msg["From"] = _from - mime_msg["To"] = ", ".join(_to) - mime_msg.attach(_body) - return mime_msg - + attachments = rejection_pdf and [rejection_pdf] or [] + + return compose_email( + from_addr=lab.getEmailAddress(), + to_addr=_to, + subj=_("%s has been rejected") % api.get_id(sample), + body=email_body, + attachments=attachments) diff --git a/bika/lims/workflow/analysisrequest/events.py b/bika/lims/workflow/analysisrequest/events.py index 8d454623d3..53d06f3619 100644 --- a/bika/lims/workflow/analysisrequest/events.py +++ b/bika/lims/workflow/analysisrequest/events.py @@ -27,8 +27,6 @@ from bika.lims.interfaces import IVerified from bika.lims.utils import changeWorkflowState from bika.lims.utils.analysisrequest import create_retest -from bika.lims.utils.analysisrequest import get_rejection_mail -from bika.lims.utils.analysisrequest import get_rejection_pdf from bika.lims.workflow import doActionFor as do_action_for from bika.lims.workflow import get_prev_status_from_history from bika.lims.workflow.analysisrequest import AR_WORKFLOW_ID From 86fa36517d60757b9f4ab3e5b62592a04ee2cf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 21 Feb 2020 23:07:54 +0100 Subject: [PATCH 4/5] Allow to modify the email template for rejection notification --- CHANGES.rst | 1 + bika/lims/browser/analysisrequest/reject.py | 43 +++++-------------- .../templates/analysisrequest_retract_mail.pt | 40 ----------------- bika/lims/content/bikasetup.py | 27 +++++++++++- bika/lims/utils/analysisrequest.py | 22 +++++++--- 5 files changed, 55 insertions(+), 78 deletions(-) delete mode 100644 bika/lims/browser/analysisrequest/templates/analysisrequest_retract_mail.pt diff --git a/CHANGES.rst b/CHANGES.rst index 8925b6f1dc..08f09ec25f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ Changelog **Added** +- #1553 Allow to modify the email template for rejection notification - #1549 Added registry profile for jQuery UI settings - #1544 Progress indicator for Batch listing - #1536 Integrated Setup and Profiles from senaite.lims diff --git a/bika/lims/browser/analysisrequest/reject.py b/bika/lims/browser/analysisrequest/reject.py index 8000ec13db..fbb48031a5 100644 --- a/bika/lims/browser/analysisrequest/reject.py +++ b/bika/lims/browser/analysisrequest/reject.py @@ -22,10 +22,19 @@ from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile -class AnalysisRequestRejectBase(object): +class AnalysisRequestRejectPdfView(BrowserView): """ - Provides helper methods that ease the work with rejection reasons + View that renders the template to be used for the generation of a pdf to + be attached in the email for the notification of an Analysis Request + rejection action. """ + template = ViewPageTemplateFile("templates/analysisrequest_retract_pdf.pt") + + def __init__(self, context, request): + super(AnalysisRequestRejectPdfView, self).__init__(context, request) + + def __call__(self): + return self.template() def get_rejection_reasons(self, keyword=None): """ @@ -49,33 +58,3 @@ def get_rejection_reasons(self, keyword=None): return rejection_reasons.get(keyword, '') and [rejection_reasons.get(keyword, '')] or [] return rejection_reasons.get(keyword, []) - -class AnalysisRequestRejectEmailView(BrowserView, AnalysisRequestRejectBase): - """ - View that renders the template to be attached in the body of the email - for the notification of an Analysis Request rejection action. - """ - - template = ViewPageTemplateFile("templates/analysisrequest_retract_mail.pt") - - def __init__(self, context, request): - super(AnalysisRequestRejectEmailView, self).__init__(context, request) - - def __call__(self): - return self.template() - - -class AnalysisRequestRejectPdfView(BrowserView, AnalysisRequestRejectBase): - """ - View that renders the template to be used for the generation of a pdf to - be attached in the email for the notification of an Analysis Request - rejection action. - """ - - template = ViewPageTemplateFile("templates/analysisrequest_retract_pdf.pt") - - def __init__(self, context, request): - super(AnalysisRequestRejectPdfView, self).__init__(context, request) - - def __call__(self): - return self.template() diff --git a/bika/lims/browser/analysisrequest/templates/analysisrequest_retract_mail.pt b/bika/lims/browser/analysisrequest/templates/analysisrequest_retract_mail.pt deleted file mode 100644 index bc98b0ac51..0000000000 --- a/bika/lims/browser/analysisrequest/templates/analysisrequest_retract_mail.pt +++ /dev/null @@ -1,40 +0,0 @@ - - - - -

- - -
-
-
- - -

-
- -

- For further information please contact us under the following address. -

-
- -

- - -
-
- - -
-
- Phone:
- Fax:
-
-

-
diff --git a/bika/lims/content/bikasetup.py b/bika/lims/content/bikasetup.py index 46ea7ca27b..f8baa7648b 100644 --- a/bika/lims/content/bikasetup.py +++ b/bika/lims/content/bikasetup.py @@ -601,6 +601,31 @@ def getCounterTypes(self, instance=None): "via email to the Client when a Sample is rejected.") ), ), + TextField( + "EmailBodySampleRejection", + default_content_type='text/html', + default_output_type='text/x-html-safe', + schemata="Notifications", + label=_("Email body for Sample Rejection notifications"), + default="The sample $sample_link has been rejected because of the " + "following reasons:" + "

$reasons

" + "For further information, please contact us under the " + "following address.

" + "$lab_address", + widget=RichWidget( + label=_("Email body for Sample Rejection notifications"), + description=_( + "Set the text for the body of the email to be sent to the " + "Sample's client contact if the option 'Email notification on " + "Sample rejection' is enabled. You can use reserved keywords: " + "$sample_id, $sample_link, $reasons, $lab_address"), + default_mime_type='text/x-rst', + output_mime_type='text/x-html', + allow_file_upload=False, + rows=15, + ), + ), BooleanField( 'NotifyOnSampleInvalidation', schemata="Notifications", @@ -640,7 +665,7 @@ def getCounterTypes(self, instance=None): default_mime_type='text/x-rst', output_mime_type='text/x-html', allow_file_upload=False, - rows=10, + rows=15, ), ), StringField( diff --git a/bika/lims/utils/analysisrequest.py b/bika/lims/utils/analysisrequest.py index f31b1c1b9c..34775b81c6 100644 --- a/bika/lims/utils/analysisrequest.py +++ b/bika/lims/utils/analysisrequest.py @@ -19,6 +19,7 @@ # Some rights reserved, see README and LICENSE. import itertools +from string import Template import six from Products.Archetypes.config import UID_CATALOG @@ -45,6 +46,7 @@ from bika.lims.utils import changeWorkflowState from bika.lims.utils import copy_field_values from bika.lims.utils import createPdf +from bika.lims.utils import get_link from bika.lims.utils import tmpID from bika.lims.workflow import ActionHandlerPool from bika.lims.workflow import doActionFor @@ -520,13 +522,23 @@ def get_rejection_pdf(sample): def get_rejection_mail(sample, rejection_pdf=None): """Generates an email to sample contacts with rejection reasons """ - # Avoid circular dependencies - from bika.lims.browser.analysisrequest.reject import \ - AnalysisRequestRejectEmailView + # Get the reasons + reasons = sample.getRejectionReasons() + reasons = reasons and reasons[0] or {} + reasons = reasons.get("selected", []) + [reasons.get("other")] + reasons = filter(None, reasons) + reasons = "
- ".join(reasons) # Render the email body - tpl = AnalysisRequestRejectEmailView(sample, api.get_request()) - email_body = tpl.template() + setup = api.get_setup() + lab_address = setup.laboratory.getPrintAddress() + email_body = Template(setup.getEmailBodySampleRejection()) + email_body = email_body.safe_substitute({ + "lab_address": "
".join(lab_address), + "reasons": reasons and "
-{}".format(reasons) or "", + "sample_id": api.get_id(sample), + "sample_link": get_link(api.get_url(sample), api.get_id(sample)) + }) def to_valid_email_address(contact): if not contact: From b318b8c87c525e84ed60686d57393a7ed3782e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Fri, 21 Feb 2020 23:37:55 +0100 Subject: [PATCH 5/5] No need of constructor --- bika/lims/browser/analysisrequest/reject.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bika/lims/browser/analysisrequest/reject.py b/bika/lims/browser/analysisrequest/reject.py index fbb48031a5..26dc2c6be1 100644 --- a/bika/lims/browser/analysisrequest/reject.py +++ b/bika/lims/browser/analysisrequest/reject.py @@ -30,9 +30,6 @@ class AnalysisRequestRejectPdfView(BrowserView): """ template = ViewPageTemplateFile("templates/analysisrequest_retract_pdf.pt") - def __init__(self, context, request): - super(AnalysisRequestRejectPdfView, self).__init__(context, request) - def __call__(self): return self.template()