Ejemplo n.º 1
0
    def __call__(self):
        if 'submitted' in self.request:
            self.items = self.context.objectValues()
            self.pricelist_content = self.lineitems_pt()

            portal = context.portal_url.getPortalObject()
            lab = context.bika_labinfo.laboratory
            request = context.REQUEST

            ar_query_results = portal.portal_mailtemplates.getTemplate(
                'bika', request.mail_template)

            headers = {}
            headers['Date'] = DateTime().rfc822()
            from_addr = headers['From'] = formataddr(
                (encode_header(lab.Title()), lab.getEmailAddress())
            )

            if 'Contact_email_address' in request:
                contact_address = request.Contact_email_address
                msg = 'portal_status_message=Pricelist sent to %s' % (
                    contact_address)
            else:
                contact = context.reference_catalog.lookupObject(request.Contact_uid)
                contact_address = formataddr(
                    (encode_header(contact.getFullname()),
                      contact.getEmailAddress())
                )
                msg = 'portal_status_message=Pricelist sent to %s at %s' % (
                    contact.Title(), contact.getEmailAddress())

            to_addrs = []
            to_addr = headers['To'] = contact_address
            to_addrs.append(to_addr)
            # send copy to lab
            to_addrs.append(from_addr)

            to_addrs = tuple(to_addrs)
            info = {'request': request,
                    'pricelist': context,
                    'portal': portal}

            message = pmt.createMessage(
                'bika', request.mail_template, info, headers, text_format='html')
            sendmail(portal, from_addr, to_addrs, message)

            request.RESPONSE.redirect('%s?%s' % (context.absolute_url(), msg))

            return self.template()
        else:
            return self.form_template()
Ejemplo n.º 2
0
    def __call__(self):
        if 'submitted' in self.request:
            self.items = self.context.objectValues()
            self.pricelist_content = self.lineitems_pt()

            portal = context.portal_url.getPortalObject()
            lab = context.bika_labinfo.laboratory
            request = context.REQUEST

            ar_query_results = portal.portal_mailtemplates.getTemplate(
                'bika', request.mail_template)

            headers = {}
            headers['Date'] = DateTime().rfc822()
            from_addr = headers['From'] = formataddr(
                (encode_header(lab.Title()), lab.getEmailAddress()))

            if 'Contact_email_address' in request:
                contact_address = request.Contact_email_address
                msg = 'portal_status_message=Pricelist sent to %s' % (
                    contact_address)
            else:
                contact = context.reference_catalog.lookupObject(
                    request.Contact_uid)
                contact_address = formataddr(
                    (encode_header(contact.getFullname()),
                     contact.getEmailAddress()))
                msg = 'portal_status_message=Pricelist sent to %s at %s' % (
                    contact.Title(), contact.getEmailAddress())

            to_addrs = []
            to_addr = headers['To'] = contact_address
            to_addrs.append(to_addr)
            # send copy to lab
            to_addrs.append(from_addr)

            to_addrs = tuple(to_addrs)
            info = {'request': request, 'pricelist': context, 'portal': portal}

            message = pmt.createMessage('bika',
                                        request.mail_template,
                                        info,
                                        headers,
                                        text_format='html')
            sendmail(portal, from_addr, to_addrs, message)

            request.RESPONSE.redirect('%s?%s' % (context.absolute_url(), msg))

            return self.template()
        else:
            return self.form_template()
Ejemplo n.º 3
0
    def workflow_script_ship(self):
        #send the email
        lab = self.bika_setup.laboratory
        sender = formataddr((encode_header(lab.getName()), self.getFromEmailAddress()))

        client = self.getClient()
        receiver = formataddr((encode_header(client.getName()), self.getToEmailAddress()))

        subject = "Samples Shipped"
        body = "Automatic email:\n"
        body += 'The samples \"%s\" has been shipped.' % self.getStringified(self.getSamplesList())
        self.send_mail(sender, receiver, subject, body)

        self.free_storage_locations()
Ejemplo n.º 4
0
 def sendAlertEmail(self):
     # Send an alert email
     laboratory = self.context.bika_setup.laboratory
     subject = self.request.get('subject')
     to = self.request.get('to')
     body = self.request.get('body')
     body = "<br/>".join(body.split("\r\n"))
     mime_msg = MIMEMultipart('related')
     mime_msg['Subject'] = subject
     mime_msg['From'] = formataddr((encode_header(laboratory.getName()),
                                    laboratory.getEmailAddress()))
     mime_msg['To'] = to
     msg_txt = MIMEText(safe_unicode(body).encode('utf-8'), _subtype='html')
     mime_msg.preamble = 'This is a multi-part MIME message.'
     mime_msg.attach(msg_txt)
     succeed = False
     try:
         host = getToolByName(self.context, 'MailHost')
         host.send(mime_msg.as_string(), immediate=True)
     except Exception, msg:
         ar = self.context.id
         logger.error("Panic level email %s: %s" % (ar, str(msg)))
         message = _('Unable to send an email to alert client '
                     'that some results exceeded the panic levels') \
                                          + (": %s" % str(msg))
         self.addMessage(message, 'warning')
Ejemplo n.º 5
0
 def sendAlertEmail(self):
     # Send an alert email
     laboratory = self.context.bika_setup.laboratory
     subject = self.request.get('subject')
     to = self.request.get('to')
     body = self.request.get('body')
     body = "<br/>".join(body.split("\r\n"))
     mime_msg = MIMEMultipart('related')
     mime_msg['Subject'] = subject
     mime_msg['From'] = formataddr(
                 (encode_header(laboratory.getName()),
                  laboratory.getEmailAddress()))
     mime_msg['To'] = to
     msg_txt = MIMEText(safe_unicode(body).encode('utf-8'),
                        _subtype='html')
     mime_msg.preamble = 'This is a multi-part MIME message.'
     mime_msg.attach(msg_txt)
     succeed = False
     try:
         host = getToolByName(self.context, 'MailHost')
         host.send(mime_msg.as_string(), immediate=True)
     except Exception, msg:
         ar = self.context.id
         logger.error("Panic level email %s: %s" % (ar, str(msg)))
         message = _('Unable to send an email to alert client '
                     'that some results exceeded the panic levels') \
                                          + (": %s" % str(msg))
         self.addMessage(message, 'warning')
Ejemplo n.º 6
0
    def workflow_script_dispatch_shipment(self):
        """executed after shipment state transition "dispatch"
        """
        # free positions kits occupy
        kits = self.getKits()
        w_tool = getToolByName(self, 'portal_workflow')
        for kit in kits:
            kit.setStorageLocation('')
            w_tool.doActionFor(kit, 'ship')
            kit.reindexObject()

        # Set shipment's date dispatched
        now = DateTime()
        self.setDateDispatched(now)

        to_contact = self.getToContact()
        from_contact = self.getFromContact()
        client = to_contact.aq_parent
        lab = self.bika_setup.laboratory
        subject = "Kits dispatched from {}".format(lab.getName())
        sender = formataddr((lab.getName(), from_contact.getEmailAddress()))
        receiver = formataddr((encode_header(client.getName()), to_contact.getEmailAddress()))
        body = "Automatic email:\n"
        body += 'The shipment \"%s\" has been sent from the Biobank \"%s\".' % (self.Title(), lab.getName())
        self.send_mail(sender, receiver, subject, body)
Ejemplo n.º 7
0
def send_panic_email(view):
    ar = view.context
    if not IAnalysisRequest.providedBy(ar):
        return False

    if not ar.has_analyses_in_panic():
        addMessage(view, _("No results exceed the panic levels"), 'warning')
        return False

    # Send an alert email
    laboratory = view.context.bika_setup.laboratory
    subject = view.request.get('subject')
    to = view.request.get('to')
    body = view.request.get('email_body')
    body = "<br/>".join(body.split("\r\n"))
    mime_msg = MIMEMultipart('related')
    mime_msg['Subject'] = subject
    mime_msg['From'] = formataddr(
        (encode_header(laboratory.getName()),
         laboratory.getEmailAddress()))
    mime_msg['To'] = to
    msg_txt = MIMEText(safe_unicode(body).encode('utf-8'), _subtype='html')
    mime_msg.preamble = 'This is a multi-part MIME message.'
    mime_msg.attach(msg_txt)
    try:
        host = getToolByName(view.context, 'MailHost')
        host.send(mime_msg.as_string(), immediate=True)
    except Exception, msg:
        ar = view.context.id
        logger.error("Panic level email %s: %s" % (ar, str(msg)))
        message = _('Unable to send an email to alert client '
                    'that some results exceeded the panic levels') \
                  + (": %s" % str(msg))
        addMessage(view, message, 'warning')
        return False
Ejemplo n.º 8
0
    def send_panic_email(self):
        # Send an alert email
        setup = api.get_setup()
        laboratory = setup.laboratory
        subject = self.request.get('subject')
        to = self.request.get('to')
        body = self.request.get('email_body')
        body = "<br/>".join(body.split("\r\n"))
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = subject
        mime_msg['From'] = formataddr(
            (encode_header(laboratory.getName()),
             laboratory.getEmailAddress()))
        mime_msg['To'] = to
        msg_txt = MIMEText(safe_unicode(body).encode('utf-8'), _subtype='html')
        mime_msg.preamble = 'This is a multi-part MIME message.'
        mime_msg.attach(msg_txt)
        try:
            host = api.get_tool("MailHost")
            host.send(mime_msg.as_string(), immediate=True)
        except Exception, msg:
            sample_id = api.get_id(self.sample)
            logger.error("Panic level email %s: %s" % (sample_id, str(msg)))
            message = _("Unable to send an email to alert client "
                        "that some results exceeded the panic levels")
            message = "{}: {}".format(message, str(msg))

            return self.redirect(self.back_url, message, "warning")
Ejemplo n.º 9
0
    def emailInvoice(self, templateHTML, to=[]):
        """
        Send the invoice via email.
        :param templateHTML: The invoice template in HTML, ready to be send.
        :param to: A list with the addresses to send the invoice.
        """
        ar = self.aq_parent
        # SMTP errors are silently ignored if server is in debug mode
        debug_mode = App.config.getConfiguration().debug_mode
        # Useful variables
        lab = ar.bika_setup.laboratory
        # Compose and send email.
        subject = t(_('Invoice')) + ' ' + ar.getInvoice().getId()
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = subject
        mime_msg['From'] = formataddr(
            (encode_header(lab.getName()), lab.getEmailAddress()))
        mime_msg.preamble = 'This is a multi-part MIME message.'
        msg_txt_t = MIMEText(templateHTML.encode('utf-8'), _subtype='html')
        mime_msg.attach(msg_txt_t)

        # Build the responsible's addresses
        mngrs = ar.getResponsible()
        for mngrid in mngrs['ids']:
            name = mngrs['dict'][mngrid].get('name', '')
            email = mngrs['dict'][mngrid].get('email', '')
            if (email != ''):
                to.append(formataddr((encode_header(name), email)))
        # Build the client's address
        caddress = ar.aq_parent.getEmailAddress()
        cname = ar.aq_parent.getName()
        if (caddress != ''):
            to.append(formataddr((encode_header(cname), caddress)))
        if len(to) > 0:
            # Send the emails
            mime_msg['To'] = ','.join(to)
            try:
                host = getToolByName(ar, 'MailHost')
                host.send(mime_msg.as_string(), immediate=True)
            except SMTPServerDisconnected as msg:
                pass
                if not debug_mode:
                    raise SMTPServerDisconnected(msg)
            except SMTPRecipientsRefused as msg:
                raise WorkflowException(str(msg))
Ejemplo n.º 10
0
    def emailInvoice(self, templateHTML, to=[]):
        """
        Send the invoice via email.
        :param templateHTML: The invoice template in HTML, ready to be send.
        :param to: A list with the addresses to send the invoice.
        """
        ar = self.aq_parent
        # SMTP errors are silently ignored if server is in debug mode
        debug_mode = App.config.getConfiguration().debug_mode
        # Useful variables
        lab = ar.bika_setup.laboratory
        # Compose and send email.
        subject = t(_('Invoice')) + ' ' + ar.getInvoice().getId()
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = subject
        mime_msg['From'] = formataddr(
            (encode_header(lab.getName()), lab.getEmailAddress()))
        mime_msg.preamble = 'This is a multi-part MIME message.'
        msg_txt_t = MIMEText(templateHTML.encode('utf-8'), _subtype='html')
        mime_msg.attach(msg_txt_t)

        # Build the responsible's addresses
        mngrs = ar.getResponsible()
        for mngrid in mngrs['ids']:
            name = mngrs['dict'][mngrid].get('name', '')
            email = mngrs['dict'][mngrid].get('email', '')
            if (email != ''):
                to.append(formataddr((encode_header(name), email)))
        # Build the client's address
        caddress = ar.aq_parent.getEmailAddress()
        cname = ar.aq_parent.getName()
        if (caddress != ''):
                to.append(formataddr((encode_header(cname), caddress)))
        if len(to) > 0:
            # Send the emails
            mime_msg['To'] = ','.join(to)
            try:
                host = getToolByName(ar, 'MailHost')
                host.send(mime_msg.as_string(), immediate=True)
            except SMTPServerDisconnected as msg:
                pass
                if not debug_mode:
                    raise SMTPServerDisconnected(msg)
            except SMTPRecipientsRefused as msg:
                raise WorkflowException(str(msg))
Ejemplo n.º 11
0
    def workflow_script_ready_to_ship(self):
        #send the email
        lab = self.bika_setup.laboratory
        sender = formataddr((encode_header(lab.getName()), self.getFromEmailAddress()))

        client = self.getClient()
        receiver = formataddr((encode_header(client.getName()), self.getToEmailAddress()))

        samples_text = self.getStringified(self.getSamplesList())

        subject = "Samples ready to ship"
        body = "Automatic email:\n"
        body += 'The samples \"%s\" are ready to ship.' % samples_text

        # print('------------')
        # print(sender)
        # print(receiver)
        # print(body)

        self.send_mail(sender, receiver, subject, body)
Ejemplo n.º 12
0
 def workflow_script_collect(self):
     """executed after shipment state transition to collect
     """
     to_contact = self.getToContact()
     from_contact = self.getFromContact()
     client = to_contact.aq_parent
     subject = "Shipment ready for collection"
     sender = formataddr((encode_header(client.getName()), to_contact.getEmailAddress()))
     lab = self.bika_setup.laboratory
     receiver = formataddr((lab.getName(), from_contact.getEmailAddress()))
     body = "Automatic email:\n"
     body += '\"%s\" sent to client \"%s\" ready for collection.' % (self.Title(), client.getName())
     self.send_mail(sender, receiver, subject, body)
Ejemplo n.º 13
0
 def workflow_script_receive_back(self):
     """ Executed after shipment received back by the biobank
     """
     to_contact = self.getToContact()
     from_contact = self.getFromContact()
     client = to_contact.aq_parent
     subject = "Shipment reached the Biobank"
     lab = self.bika_setup.laboratory
     sender = formataddr((lab.getName(), from_contact.getEmailAddress()))
     receiver = formataddr((encode_header(client.getName()), to_contact.getEmailAddress()))
     body = "Automatic email:\n"
     body += 'The shipment \"%s\" sent back is arrived at the Biobank \"%s\".' % (self.Title(), lab.getName())
     self.send_mail(sender, receiver, subject, body)
Ejemplo n.º 14
0
 def workflow_script_collect(self):
     """ Executed after shipment ready for collection from the client
     """
     to_contact = self.getToContact()
     from_contact = self.getFromContact()
     client = to_contact.aq_parent
     subject = "Shipment ready for collection"
     sender = formataddr((encode_header(client.getName()), to_contact.getEmailAddress()))
     lab = self.bika_setup.laboratory
     receiver = formataddr((lab.getName(), from_contact.getEmailAddress()))
     body = "Automatic email:\n"
     body += 'The shipment \"%s\" sent to the client \"%s\" is ready for collection.' % (self.Title(), client.getName())
     self.send_mail(sender, receiver, subject, body)
Ejemplo n.º 15
0
 def sendEmail(self):
     added = []
     to = ''
     for analysis in self.analyses:
         department = analysis.getService().getDepartment()
         if department is None:
             continue
         department_id = department.UID()
         if department_id in added:
             continue
         added.append(department_id)
         manager = department.getManager()
         if manager is None:
             continue
         manager_id = manager.UID()
         if manager_id not in added and manager.getEmailAddress():
             added.append(manager_id)
             name = safe_unicode(manager.getFullname()).encode('utf-8')
             email = safe_unicode(manager.getEmailAddress()).encode('utf-8')
             to = '%s, %s' % (to, formataddr((encode_header(name), email)))
     html = safe_unicode(self.template()).encode('utf-8')
     lab = self.context.bika_setup.laboratory
     mime_msg = MIMEMultipart('related')
     mime_msg['Subject'] = self.title
     mime_msg['From'] = formataddr(
         (encode_header(lab.getName()),
          lab.getEmailAddress()))
     mime_msg['To'] = to
     mime_msg.preamble = 'This is a multi-part MIME message.'
     msg_txt = MIMEText(html, _subtype='html')
     mime_msg.attach(msg_txt)
     # Send the email
     try:
         host = getToolByName(self.context, 'MailHost')
         host.send(mime_msg.as_string(), immediate=True)
     except SMTPServerDisconnected as msg:
         raise SMTPServerDisconnected(msg)
     except SMTPRecipientsRefused as msg:
         raise WorkflowException(str(msg))
Ejemplo n.º 16
0
 def sendEmail(self):
     added = []
     to = ''
     for analysis in self.analyses:
         department = analysis.getService().getDepartment()
         if department is None:
             continue
         department_id = department.UID()
         if department_id in added:
             continue
         added.append(department_id)
         manager = department.getManager()
         if manager is None:
             continue
         manager_id = manager.UID()
         if manager_id not in added and manager.getEmailAddress():
             added.append(manager_id)
             name = safe_unicode(manager.getFullname()).encode('utf-8')
             email = safe_unicode(manager.getEmailAddress()).encode('utf-8')
             to = '%s, %s' % (to, formataddr((encode_header(name), email)))
     html = safe_unicode(self.template()).encode('utf-8')
     lab = self.context.bika_setup.laboratory
     mime_msg = MIMEMultipart('related')
     mime_msg['Subject'] = self.title
     mime_msg['From'] = formataddr(
         (encode_header(lab.getName()),
          lab.getEmailAddress()))
     mime_msg['To'] = to
     mime_msg.preamble = 'This is a multi-part MIME message.'
     msg_txt = MIMEText(html, _subtype='html')
     mime_msg.attach(msg_txt)
     # Send the email
     try:
         host = getToolByName(self.context, 'MailHost')
         host.send(mime_msg.as_string(), immediate=True)
     except SMTPServerDisconnected as msg:
         raise SMTPServerDisconnected(msg)
     except SMTPRecipientsRefused as msg:
         raise WorkflowException(str(msg))
Ejemplo n.º 17
0
 def workflow_script_receive_shipment(self):
     """executed after shipment state transition to received
     """
     to_contact = self.getToContact()
     from_contact = self.getFromContact()
     client = to_contact.aq_parent
     subject = "Shipment Received"
     sender = formataddr(
         (encode_header(client.getName()), to_contact.getEmailAddress()))
     lab = self.bika_setup.laboratory
     receiver = formataddr((lab.getName(), from_contact.getEmailAddress()))
     body = "Automatic email:\n"
     body += '\"%s\" sent to client \"%s\" has been received.' % (
         self.Title(), client.getName())
     self.send_mail(sender, receiver, subject, body)
Ejemplo n.º 18
0
 def emailInvoice(self, templateHTML, to=[]):
     """
     Add the patient's insurance number in the receivers
     :param templateHTML: the html to render. We override it.
     :param to: the list with the receivers. Void in this case.
     """
     # Check if the patient's "Send invoices to the insurance company" checkbox is checked.
     sendtoinsurance = self.context.Schema()['Patient'].get(self.context).getInvoiceToInsuranceCompany()
     if sendtoinsurance:
         # Obtains the insurance company object
         insurancecompany = self.context.Schema()['Patient'].get(self.context).getInsuranceCompany()
         # Build the insurance company's address
         icaddress = insurancecompany.getEmailAddress()
         icname = insurancecompany.getName()
         if (icaddress != ''):
                 to.append(formataddr((encode_header(icname), icaddress)))
     super(InvoiceCreate, self).emailInvoice(templateHTML, to)
Ejemplo n.º 19
0
 def emailInvoice(self, templateHTML, to=[]):
     """
     Add the patient's insurance number in the receivers
     :param templateHTML: the html to render. We override it.
     :param to: the list with the receivers. Void in this case.
     """
     # Check if the patient's "Send invoices to the insurance company" checkbox is checked.
     sendtoinsurance = self.context.Schema()['Patient'].get(
         self.context).getInvoiceToInsuranceCompany()
     if sendtoinsurance:
         # Obtains the insurance company object
         insurancecompany = self.context.Schema()['Patient'].get(
             self.context).getInsuranceCompany()
         # Build the insurance company's address
         icaddress = insurancecompany.getEmailAddress()
         icname = insurancecompany.getName()
         if (icaddress != ''):
             to.append(formataddr((encode_header(icname), icaddress)))
     super(InvoiceCreate, self).emailInvoice(templateHTML, to)
Ejemplo n.º 20
0
    def workflow_action_retract_ar(self):
        workflow = getToolByName(self.context, 'portal_workflow')
        # AR should be retracted
        # Can't transition inactive ARs
        if not isActive(self.context):
            message = _('Item is inactive.')
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.request.response.redirect(self.context.absolute_url())
            return

        # 1. Copies the AR linking the original one and viceversa
        ar = self.context
        newar = self.cloneAR(ar)

        # 2. The old AR gets a status of 'invalid'
        workflow.doActionFor(ar, 'retract_ar')

        # 3. The new AR copy opens in status 'to be verified'
        changeWorkflowState(newar, 'bika_ar_workflow', 'to_be_verified')

        # 4. The system immediately alerts the client contacts who ordered
        # the results, per email and SMS, that a possible mistake has been
        # picked up and is under investigation.
        # A much possible information is provided in the email, linking
        # to the AR online.
        laboratory = self.context.bika_setup.laboratory
        lab_address = "<br/>".join(laboratory.getPrintAddress())
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = t(_("Erroneus result publication from ${request_id}",
                                mapping={"request_id": ar.getRequestID()}))
        mime_msg['From'] = formataddr(
            (encode_header(laboratory.getName()),
             laboratory.getEmailAddress()))
        to = []
        contact = ar.getContact()
        if contact:
            to.append(formataddr((encode_header(contact.Title()),
                                   contact.getEmailAddress())))
        for cc in ar.getCCContact():
            formatted = formataddr((encode_header(cc.Title()),
                                   cc.getEmailAddress()))
            if formatted not in to:
                to.append(formatted)

        managers = self.context.portal_groups.getGroupMembers('LabManagers')
        for bcc in managers:
            user = self.portal.acl_users.getUser(bcc)
            if user:
                uemail = user.getProperty('email')
                ufull = user.getProperty('fullname')
                formatted = formataddr((encode_header(ufull), uemail))
                if formatted not in to:
                    to.append(formatted)
        mime_msg['To'] = ','.join(to)
        aranchor = "<a href='%s'>%s</a>" % (ar.absolute_url(),
                                            ar.getRequestID())
        naranchor = "<a href='%s'>%s</a>" % (newar.absolute_url(),
                                             newar.getRequestID())
        addremarks = ('addremarks' in self.request
                      and ar.getRemarks()) \
                    and ("<br/><br/>"
                         + _("Additional remarks:")
                         + "<br/>"
                         + ar.getRemarks().split("===")[1].strip()
                         + "<br/><br/>") \
                    or ''
        sub_d = dict(request_link=aranchor,
                     new_request_link=naranchor,
                     remarks=addremarks,
                     lab_address=lab_address)
        body = Template("Some errors have been detected in the results report "
                        "published from the Analysis Request $request_link. The Analysis "
                        "Request $new_request_link has been created automatically and the "
                        "previous has been invalidated.<br/>The possible mistake "
                        "has been picked up and is under investigation.<br/><br/>"
                        "$remarks $lab_address").safe_substitute(sub_d)
        msg_txt = MIMEText(safe_unicode(body).encode('utf-8'),
                           _subtype='html')
        mime_msg.preamble = 'This is a multi-part MIME message.'
        mime_msg.attach(msg_txt)
        try:
            host = getToolByName(self.context, 'MailHost')
            host.send(mime_msg.as_string(), immediate=True)
        except Exception as msg:
            message = _('Unable to send an email to alert lab '
                        'client contacts that the Analysis Request has been '
                        'retracted: ${error}',
                        mapping={'error': safe_unicode(msg)})
            self.context.plone_utils.addPortalMessage(message, 'warning')

        message = _('${items} invalidated.',
                    mapping={'items': ar.getRequestID()})
        self.context.plone_utils.addPortalMessage(message, 'warning')
        self.request.response.redirect(newar.absolute_url())
Ejemplo n.º 21
0
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
    """
    arid = analysisrequest.getRequestID()

    # 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
    from bika.lims.browser.analysisrequest.reject import AnalysisRequestRejectPdfView
    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, tmpID())
        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)
        atts = analysisrequest.getAttachment() + [att] if \
                analysisrequest.getAttachment() else [att]
        atts = [a.UID() for a in atts]
        analysisrequest.setAttachment(atts)
        os.remove(pdf_fn)

    # This is the message for the email's body
    from bika.lims.browser.analysisrequest.reject import AnalysisRequestRejectEmailView
    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:
        pass

    return True
Ejemplo n.º 22
0
    def notify_ar_retract(self, ar, newar):
        bika_setup = api.get_bika_setup()
        laboratory = bika_setup.laboratory
        lab_address = "<br/>".join(laboratory.getPrintAddress())
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = t(
            _("Erroneus result publication from ${request_id}",
              mapping={"request_id": ar.getId()}))
        mime_msg['From'] = formataddr((encode_header(laboratory.getName()),
                                       laboratory.getEmailAddress()))
        to = []
        contact = ar.getContact()
        if contact:
            to.append(
                formataddr((encode_header(contact.Title()),
                            contact.getEmailAddress())))
        for cc in ar.getCCContact():
            formatted = formataddr(
                (encode_header(cc.Title()), cc.getEmailAddress()))
            if formatted not in to:
                to.append(formatted)

        managers = self.context.portal_groups.getGroupMembers('LabManagers')
        for bcc in managers:
            user = self.portal.acl_users.getUser(bcc)
            if user:
                uemail = user.getProperty('email')
                ufull = user.getProperty('fullname')
                formatted = formataddr((encode_header(ufull), uemail))
                if formatted not in to:
                    to.append(formatted)
        mime_msg['To'] = ','.join(to)
        aranchor = "<a href='%s'>%s</a>" % (ar.absolute_url(), ar.getId())
        naranchor = "<a href='%s'>%s</a>" % (newar.absolute_url(),
                                             newar.getId())
        addremarks = ('addremarks' in self.request and ar.getRemarks()) and (
            "<br/><br/>" + _("Additional remarks:") + "<br/>" +
            ar.getRemarks().split("===")[1].strip() + "<br/><br/>") or ''
        sub_d = dict(request_link=aranchor,
                     new_request_link=naranchor,
                     remarks=addremarks,
                     lab_address=lab_address)
        body = Template(
            "Some errors have been detected in the results report "
            "published from the Analysis Request $request_link. The Analysis "
            "Request $new_request_link has been created automatically and the "
            "previous has been invalidated.<br/>The possible mistake "
            "has been picked up and is under investigation.<br/><br/>"
            "$remarks $lab_address").safe_substitute(sub_d)
        msg_txt = MIMEText(safe_unicode(body).encode('utf-8'), _subtype='html')
        mime_msg.preamble = 'This is a multi-part MIME message.'
        mime_msg.attach(msg_txt)
        try:
            host = getToolByName(self.context, 'MailHost')
            host.send(mime_msg.as_string(), immediate=True)
        except Exception as msg:
            message = _(
                'Unable to send an email to alert lab '
                'client contacts that the Analysis Request has been '
                'retracted: ${error}',
                mapping={'error': safe_unicode(msg)})
            self.context.plone_utils.addPortalMessage(message, 'warning')
Ejemplo n.º 23
0
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
    """
    arid = analysisrequest.getRequestID()

    # 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
    from bika.lims.browser.analysisrequest.reject import AnalysisRequestRejectPdfView
    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_success = createPdf(html, pdf_fn)
    pdf_data = None
    if pdf_success:
        # Attach the pdf to the Analysis Request
        pdf_data = open(pdf_fn, 'rb').read()
        attid = analysisrequest.aq_parent.generateUniqueId('Attachment')
        att = _createObjectByType("Attachment", analysisrequest.aq_parent,
                                  tmpID())
        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)
        atts = analysisrequest.getAttachment() + [att] if \
                analysisrequest.getAttachment() else [att]
        atts = [a.UID() for a in atts]
        analysisrequest.setAttachment(atts)
        os.remove(pdf_fn)

    # This is the message for the email's body
    from bika.lims.browser.analysisrequest.reject import AnalysisRequestRejectEmailView
    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_success:
        attachPdf(mime_msg, pdf_data, filename)

    try:
        host = getToolByName(analysisrequest, 'MailHost')
        host.send(mime_msg.as_string(), immediate=True)
    except:
        pass

    return True
Ejemplo n.º 24
0
    def __call__(self):

        rc = getToolByName(self.context, REFERENCE_CATALOG)
        workflow = getToolByName(self.context, 'portal_workflow')

        laboratory = self.context.bika_setup.laboratory
        BatchEmail = self.context.bika_setup.getBatchEmail()
        BatchFax = self.context.bika_setup.getBatchFax()

        # group analysis requests by contact
        ARs_by_contact = {}
        for ar in self.analysis_requests:
            contact_uid = ar.getContact().UID()
            if contact_uid not in ARs_by_contact:
                ARs_by_contact[contact_uid] = []
            ARs_by_contact[contact_uid].append(ar)

        for contact_uid, ars in ARs_by_contact.items():
            ars.sort()
            self.contact = ars[0].getContact()
            self.pub_pref = self.contact.getPublicationPreference()
            batch_size = 'email' in self.pub_pref and BatchEmail or \
                         'fax' in self.pub_pref and BatchFax or 1

            # send batches of ARs to each contact
            for b in range(0, len(ars), batch_size):
                self.batch = ars[b:b+batch_size]
                self.any_accredited = False
                self.any_drymatter = False
                # get all services from all requests in this batch into a
                # dictionary:
                #   {'Point Of Capture': {'Category': [service,service,...]}}
                self.services = {}
                for ar in self.batch:
                    if ar.getReportDryMatter():
                        self.any_drymatter = True
                    states = ("verified", "published")
                    for analysis in ar.getAnalyses(full_objects=True,
                                                   review_state=states):
                        service = analysis.getService()
                        poc = POINTS_OF_CAPTURE.getValue(service.getPointOfCapture())
                        cat = service.getCategoryName()
                        if poc not in self.services:
                            self.services[poc] = {}
                        if cat not in self.services[poc]:
                            self.services[poc][cat] = []
                        self.services[poc][cat].append(service)
                        if (service.getAccredited()):
                            self.any_accredited = True

                # compose and send email
                if 'email' in self.pub_pref:
                    mime_msg = MIMEMultipart('related')
                    mime_msg['Subject'] = self.get_mail_subject()
                    mime_msg['From'] = formataddr(
                        (encode_header(laboratory.getName()),
                         laboratory.getEmailAddress()))
                    mime_msg['To'] = formataddr(
                        (encode_header(self.contact.getFullname()),
                         self.contact.getEmailAddress()))
                    mime_msg.preamble = 'This is a multi-part MIME message.'
                    ar_results = self.ar_results()
                    msg_txt = MIMEText(ar_results, _subtype='html')
                    mime_msg.attach(msg_txt)

                    #XXX
                    open(join(Globals.INSTANCE_HOME,'var','ar_results.html'),
                                "w").write(ar_results)

                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except SMTPRecipientsRefused, msg:
                        raise WorkflowException(str(msg))
                    if self.action == 'publish':
                        for ar in self.batch:
                            try:
                                workflow.doActionFor(ar, 'publish')
                            except WorkflowException:
                                pass
                else:
                    raise Exception, "XXX pub_pref %s" % self.pub_pref
Ejemplo n.º 25
0
    def __call__(self):
        workflow = getToolByName(self.context, 'portal_workflow')
        # SMTP errors are silently ignored if server is in debug mode
        self.debug_mode = App.config.getConfiguration().debug_mode
        # PDF and HTML files are written to disk if server is in debug mode
        self.out_path = join(Globals.INSTANCE_HOME, 'var') if self.debug_mode \
            else None
        self._get_user_attributes()
        self._get_lab_attributes()

        # This for loop prints each AR individually to a PDF stored in the AR,
        # and sends whatever publication is required
        for ar_nr, ar in enumerate(self.analysis_requests):
            self.any_drymatter = ar.getReportDryMatter()
            self._get_ar_attributes(ar)
            self._get_client_attribues(ar)
            self._get_batch_attributes(ar)
            self._get_sample_attributes(ar)
            self._get_contact_attributes(ar)
            self._get_categorized_services(ar)
            self._get_categorized_qcservices(ar)
            self.Footer = to_utf8(self.context.bika_setup.getResultFooter())
            out_fn = to_utf8(ar.Title())


            # Create the html report
            ar_results = safe_unicode(self.template()).encode('utf-8')
            if self.out_path:
                open(join(self.out_path, out_fn + ".html"), "w").write(ar_results)

            # Create the pdf report (will always be attached to the AR)
            pdf_outfile = join(self.out_path,
                out_fn + ".pdf") if self.out_path else None
            pdf_css = resource_filename(
                "bika.lims", "skins/bika/analysisrequest_results_pdf.css")
            ar_css = join(self.portal_url, "analysisrequest_results.css")
            ar_results = ar_results.replace(ar_css, pdf_css)
            pdf_report = createPdf(ar_results, pdf_outfile, css=pdf_css)

            if self.contact['obj']:
                recipients = [{
                    'UID': self.contact['obj'].UID(),
                    'Username': to_utf8(self.contact['obj'].getUsername()),
                    'Fullname': to_utf8(self.contact['obj'].getFullname()),
                    'EmailAddress': to_utf8(self.contact['obj'].getEmailAddress()),
                    'PublicationModes': self.contact['obj'].getPublicationPreference()
                }]
            else:
                recipients = []

            if pdf_report:
                reportid = self.context.generateUniqueId('ARReport')
                report = _createObjectByType("ARReport", ar, reportid)
                report.edit(
                    AnalysisRequest=ar.UID(),
                    Pdf=pdf_report,
                    Html=ar_results,
                    Recipients=recipients
                )
                report.unmarkCreationFlag()
                from bika.lims.idserver import renameAfterCreation

                renameAfterCreation(report)

                # Set status to published
                if self.action == 'publish':
                    try:
                        workflow.doActionFor(ar, 'publish')
                    except WorkflowException:
                        pass

                # compose and send email.
                # The managers of the departments for which the current AR has
                # at least one AS must receive always the pdf report by email.
                # https://github.com/bikalabs/Bika-LIMS/issues/1028
                mime_msg = MIMEMultipart('related')
                mime_msg['Subject'] = self.get_mail_subject(ar)[0]
                mime_msg['From'] = formataddr(
                    (encode_header(self.laboratory['obj'].getName()),
                     self.laboratory['obj'].getEmailAddress()))
                mime_msg.preamble = 'This is a multi-part MIME message.'
                msg_txt = MIMEText(ar_results, _subtype='html')
                mime_msg.attach(msg_txt)

                to = []
                mngrs = ar.getResponsible()
                for mngrid in mngrs['ids']:
                    name = mngrs['dict'][mngrid].get('name', '')
                    email = mngrs['dict'][mngrid].get('email', '')
                    if (email != ''):
                        to.append(formataddr((encode_header(name), email)))

                if len(to) > 0:
                    # Send the email to the managers
                    mime_msg['To'] = ','.join(to)
                    attachPdf(mime_msg, pdf_report, out_fn)

                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except SMTPServerDisconnected as msg:
                        pass
                        if not self.debug_mode:
                            raise SMTPServerDisconnected(msg)
                    except SMTPRecipientsRefused as msg:
                        raise WorkflowException(str(msg))

                    to = []

                # Send report to recipients
                recips = self.get_recipients(ar)
                for recip in recips:
                    if 'email' not in recip.get('pubpref', []) \
                            or not recip.get('email', ''):
                        continue

                    title = encode_header(recip.get('title', ''))
                    email = recip.get('email')
                    formatted = formataddr((title, email))

                    # Create the new mime_msg object, cause the previous one
                    # has the pdf already attached
                    mime_msg = MIMEMultipart('related')
                    mime_msg['Subject'] = self.get_mail_subject(ar)[0]
                    mime_msg['From'] = formataddr(
                        (encode_header(self.laboratory['obj'].getName()),
                         self.laboratory['obj'].getEmailAddress()))
                    mime_msg.preamble = 'This is a multi-part MIME message.'
                    msg_txt = MIMEText(ar_results, _subtype='html')
                    mime_msg.attach(msg_txt)
                    mime_msg['To'] = formatted

                    # Attach the pdf to the email if requested
                    if pdf_report and 'pdf' in recip.get('pubpref'):
                        attachPdf(mime_msg, pdf_report, out_fn)

                    # For now, I will simply ignore mail send under test.
                    if hasattr(self.portal, 'robotframework'):
                        continue

                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except SMTPServerDisconnected as msg:
                        if not self.debug_mode:
                            raise SMTPServerDisconnected(msg)
                    except SMTPRecipientsRefused as msg:
                        raise WorkflowException(str(msg))

        return [ar.RequestID for ar in self.analysis_requests]
Ejemplo n.º 26
0
    def publishFromHTML(self, aruid, results_html):
        # The AR can be published only and only if allowed
        uc = getToolByName(self.context, 'uid_catalog')
        ars = uc(UID=aruid)
        if not ars or len(ars) != 1:
            return []

        ar = ars[0].getObject();
        wf = getToolByName(ar, 'portal_workflow')
        allowed_states = ['verified', 'published']
        # Publish/Republish allowed?
        if wf.getInfoFor(ar, 'review_state') not in allowed_states:
            # Pre-publish allowed?
            if not ar.getAnalyses(review_state=allowed_states):
                return []

        # HTML written to debug file
        debug_mode = App.config.getConfiguration().debug_mode
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".html")
            logger.debug("Writing HTML for %s to %s" % (ar.Title(), tmp_fn))
            open(tmp_fn, "wb").write(results_html)

        # Create the pdf report (will always be attached to the AR)
        # we must supply the file ourself so that createPdf leaves it alone.
        pdf_fn = tempfile.mktemp(suffix=".pdf")
        pdf_report = createPdf(htmlreport=results_html, outfile=pdf_fn)

        # PDF written to debug file
        if debug_mode:
            logger.debug("Writing PDF for %s to %s" % (ar.Title(), pdf_fn))
        else:
            os.remove(pdf_fn)

        recipients = []
        contact = ar.getContact()
        lab = ar.bika_setup.laboratory
        if pdf_report:
            if contact:
                recipients = [{
                    'UID': contact.UID(),
                    'Username': to_utf8(contact.getUsername()),
                    'Fullname': to_utf8(contact.getFullname()),
                    'EmailAddress': to_utf8(contact.getEmailAddress()),
                    'PublicationModes': contact.getPublicationPreference()
                }]
            reportid = ar.generateUniqueId('ARReport')
            report = _createObjectByType("ARReport", ar, reportid)
            report.edit(
                AnalysisRequest=ar.UID(),
                Pdf=pdf_report,
                Html=results_html,
                Recipients=recipients
            )
            report.unmarkCreationFlag()
            renameAfterCreation(report)

            # Set status to prepublished/published/republished
            status = wf.getInfoFor(ar, 'review_state')
            transitions = {'verified': 'publish',
                           'published' : 'republish'}
            transition = transitions.get(status, 'prepublish')
            try:
                wf.doActionFor(ar, transition)
            except WorkflowException:
                pass

            # compose and send email.
            # The managers of the departments for which the current AR has
            # at least one AS must receive always the pdf report by email.
            # https://github.com/bikalabs/Bika-LIMS/issues/1028
            mime_msg = MIMEMultipart('related')
            mime_msg['Subject'] = self.get_mail_subject(ar)[0]
            mime_msg['From'] = formataddr(
                (encode_header(lab.getName()), lab.getEmailAddress()))
            mime_msg.preamble = 'This is a multi-part MIME message.'
            msg_txt = MIMEText(results_html, _subtype='html')
            mime_msg.attach(msg_txt)

            to = []
            mngrs = ar.getResponsible()
            for mngrid in mngrs['ids']:
                name = mngrs['dict'][mngrid].get('name', '')
                email = mngrs['dict'][mngrid].get('email', '')
                if (email != ''):
                    to.append(formataddr((encode_header(name), email)))

            if len(to) > 0:
                # Send the email to the managers
                mime_msg['To'] = ','.join(to)
                attachPdf(mime_msg, pdf_report, pdf_fn)

                try:
                    host = getToolByName(ar, 'MailHost')
                    host.send(mime_msg.as_string(), immediate=True)
                except SMTPServerDisconnected as msg:
                    logger.warn("SMTPServerDisconnected: %s." % msg)
                except SMTPRecipientsRefused as msg:
                    raise WorkflowException(str(msg))

        # Send report to recipients
        recips = self.get_recipients(ar)
        for recip in recips:
            if 'email' not in recip.get('pubpref', []) \
                    or not recip.get('email', ''):
                continue

            title = encode_header(recip.get('title', ''))
            email = recip.get('email')
            formatted = formataddr((title, email))

            # Create the new mime_msg object, cause the previous one
            # has the pdf already attached
            mime_msg = MIMEMultipart('related')
            mime_msg['Subject'] = self.get_mail_subject(ar)[0]
            mime_msg['From'] = formataddr(
            (encode_header(lab.getName()), lab.getEmailAddress()))
            mime_msg.preamble = 'This is a multi-part MIME message.'
            msg_txt = MIMEText(results_html, _subtype='html')
            mime_msg.attach(msg_txt)
            mime_msg['To'] = formatted

            # Attach the pdf to the email if requested
            if pdf_report and 'pdf' in recip.get('pubpref'):
                attachPdf(mime_msg, pdf_report, pdf_fn)

            # For now, I will simply ignore mail send under test.
            if hasattr(self.portal, 'robotframework'):
                continue

            msg_string = mime_msg.as_string()

            # content of outgoing email written to debug file
            if debug_mode:
                tmp_fn = tempfile.mktemp(suffix=".email")
                logger.debug("Writing MIME message for %s to %s" % (ar.Title(), tmp_fn))
                open(tmp_fn, "wb").write(msg_string)

            try:
                host = getToolByName(ar, 'MailHost')
                host.send(msg_string, immediate=True)
            except SMTPServerDisconnected as msg:
                logger.warn("SMTPServerDisconnected: %s." % msg)
            except SMTPRecipientsRefused as msg:
                raise WorkflowException(str(msg))

        ar.setDatePublished(DateTime())

        return [ar]
Ejemplo n.º 27
0
    def publishFromHTML(self, prouid, results_html):

        uc = getToolByName(self.context, 'uid_catalog')
        pros = uc(UID=prouid)
        if not pros or len(pros) != 1:
            return []

        pro = pros[0].getObject()

        # HTML written to debug file
        debug_mode = App.config.getConfiguration().debug_mode
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".html")
            logger.debug("Writing HTML for %s to %s" % (pro.Title(), tmp_fn))
            open(tmp_fn, "wb").write(results_html)

        # Create the pdf report (will always be attached to the Order)
        # we must supply the file ourself so that createPdf leaves it alone.
        # This version replaces 'attachment' links; probably not required,
        # so it's repeated below, without these localise_images.
        # cleanup, results_html_for_pdf = self.localise_images(results_html)
        # pdf_fn = tempfile.mktemp(suffix=".pdf")
        # pdf_report = createPdf(htmlreport=results_html_for_pdf, outfile=pdf_fn)
        # for fn in cleanup:
        #     os.remove(fn)

        pdf_fn = tempfile.mktemp(suffix=".pdf")
        pdf_report = createPdf(htmlreport=results_html, outfile=pdf_fn)

        # PDF written to debug file
        if debug_mode:
            logger.debug("Writing PDF for %s to %s" % (pro.Title(), pdf_fn))
        else:
            os.remove(pdf_fn)

        recipients = []

        # Send report to supplier
        supplier_data = self._supplier_data(pro)
        title = encode_header(supplier_data.get('title', ''))
        email = supplier_data.get('email')
        formatted = formataddr((title, email))

        # Create the new mime_msg object
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = self.get_mail_subject(pro)
        """
        	Edit this to change the From address
        	mime_msg['From'] = formataddr(
        	(encode_header(lab.getName()), lab.getEmailAddress()))
        """
        mime_msg['From'] = formataddr(("BIKA IMM", "*****@*****.**"))
        mime_msg.preamble = 'This is a multi-part MIME message.'
        msg_txt = MIMEText(results_html, _subtype='html')
        mime_msg.attach(msg_txt)
        mime_msg['To'] = formatted

        # Attach the pdf to the email if requested
        if pdf_report:
            attachPdf(mime_msg, pdf_report, pdf_fn)

        msg_string = mime_msg.as_string()

        # content of outgoing email written to debug file
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".email")
            logger.debug("Writing MIME message for %s to %s" %
                         (pro.Title(), tmp_fn))
            open(tmp_fn, "wb").write(msg_string)

        try:
            host = getToolByName(pro, 'MailHost')
            host.send(msg_string, immediate=True)
        except SMTPServerDisconnected as msg:
            logger.warn("SMTPServerDisconnected: %s." % msg)
        except SMTPRecipientsRefused as msg:
            raise WorkflowException(str(msg))

        pro.setDateDispatched(DateTime())
        return [pro]
Ejemplo n.º 28
0
    def __call__(self):

        rc = getToolByName(self.context, REFERENCE_CATALOG)
        workflow = getToolByName(self.context, 'portal_workflow')

        BatchEmail = self.context.bika_setup.getBatchEmail()

        username = self.context.portal_membership.getAuthenticatedMember().getUserName()
        self.reporter = self.user_fullname(username)
        self.reporter_email = self.user_email(username)

        # signature image
        self.reporter_signature = ""
        c = [x for x in self.bika_setup_catalog(portal_type='LabContact')
             if x.getObject().getUsername() == username]
        if c:
            sf = c[0].getObject().getSignature()
            if sf:
                self.reporter_signature = sf.absolute_url() + "/Signature"

        # lab address
        self.laboratory = laboratory = self.context.bika_setup.laboratory
        lab_address = laboratory.getPostalAddress() \
            or laboratory.getBillingAddress() \
            or laboratory.getPhysicalAddress()
        if lab_address:
            _keys = ['address', 'city', 'state', 'zip', 'country']
            _list = [lab_address.get(v) for v in _keys]
            self.lab_address = "<br/>".join(_list).replace("\n", "<br/>")
        else:
            self.lab_address = None

        # group/publish analysis requests by contact
        ARs_by_contact = {}
        for ar in self.analysis_requests:
            contact_uid = ar.getContact().UID()
            if contact_uid not in ARs_by_contact:
                ARs_by_contact[contact_uid] = []
            ARs_by_contact[contact_uid].append(ar)

        for contact_uid, ars in ARs_by_contact.items():
            ars.sort()
            self.contact = ars[0].getContact()
            self.pub_pref = self.contact.getPublicationPreference()
            batch_size = 'email' in self.pub_pref and BatchEmail or 5

            # client address
            self.client = ars[0].aq_parent
            client_address = self.client.getPostalAddress() \
                or self.contact.getBillingAddress() \
                or self.contact.getPhysicalAddress()
            if client_address:
                _keys = ['address', 'city', 'state', 'zip', 'country']
                _list = [client_address.get(v) for v in _keys]
                self.client_address = "<br/>".join(_list).replace("\n", "<br/>")
            else:
                self.client_address = None

            self.Footer = self.context.bika_setup.getResultFooter()

            # send batches of ARs to each contact
            for b in range(0, len(ars), batch_size):
                self.batch = ars[b:b+batch_size]
                self.any_accredited = False
                self.any_drymatter = False
                # get all services from all requests in this batch into a
                # dictionary:
                #   {'Point Of Capture': {'Category': [service,service,...]}}
                self.services = {}

                out_fn = "_".join([ar.Title() for ar in self.batch])

                for ar in self.batch:
                    if ar.getReportDryMatter():
                        self.any_drymatter = True
                    states = ("verified", "published")
                    for analysis in ar.getAnalyses(full_objects=True,
                                                   review_state=states):
                        service = analysis.getService()
                        poc = POINTS_OF_CAPTURE.getValue(service.getPointOfCapture())
                        cat = service.getCategoryTitle()
                        if poc not in self.services:
                            self.services[poc] = {}
                        if cat not in self.services[poc]:
                            self.services[poc][cat] = []
                        if service not in self.services[poc][cat]:
                            self.services[poc][cat].append(service)
                        if (service.getAccredited()):
                            self.any_accredited = True

                # compose and send email
                if 'email' in self.pub_pref:

                    # render template
                    ar_results = self.ar_results()

                    debug_mode = App.config.getConfiguration().debug_mode
                    if debug_mode:
                        open(join(Globals.INSTANCE_HOME,'var', out_fn + ".html"),
                             "w").write(ar_results)

                    pisa.showLogging()
                    ramdisk = StringIO()
                    pdf = pisa.CreatePDF(ar_results, ramdisk)
                    pdf_data = ramdisk.getvalue()
                    ramdisk.close()

                    if debug_mode:
                        open(join(Globals.INSTANCE_HOME,'var', out_fn + ".pdf"),
                             "wb").write(pdf_data)

                    mime_msg = MIMEMultipart('related')
                    mime_msg['Subject'] = self.get_mail_subject()
                    mime_msg['From'] = formataddr(
                        (encode_header(laboratory.getName()),
                         laboratory.getEmailAddress()))
                    mime_msg['To'] = formataddr(
                        (encode_header(self.contact.getFullname()),
                         self.contact.getEmailAddress()))
                    mime_msg.preamble = 'This is a multi-part MIME message.'
                    msg_txt = MIMEText(ar_results, _subtype='html')
                    mime_msg.attach(msg_txt)
                    if not pdf.err:
                        part = MIMEBase('application', "application/pdf")
                        part.add_header('Content-Disposition', 'attachment; filename="%s.pdf"' % out_fn)
                        part.set_payload( pdf_data )
                        Encoders.encode_base64(part)
                        mime_msg.attach(part)

                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except SMTPServerDisconnected, msg:
                        if not debug_mode:
                            raise SMTPServerDisconnected(msg)
                    except SMTPRecipientsRefused, msg:
                        raise WorkflowException(str(msg))

                    if self.action == 'publish':
                        for ar in self.batch:
                            try:
                                workflow.doActionFor(ar, 'publish')
                            except WorkflowException:
                                pass

##                    if not pdf.err:
##                        setheader = self.request.RESPONSE.setHeader
##                        setheader('Content-Type', 'application/pdf')
##                        setheader("Content-Disposition", "attachment;filename=\"%s.pdf\"" % out_fn)
##                        self.request.RESPONSE.write(pdf_data)

                else:
                    raise Exception, "XXX pub_pref %s" % self.pub_pref
Ejemplo n.º 29
0
    def publishFromHTML(self, aruid, results_html):
        # The AR can be published only and only if allowed
        uc = getToolByName(self.context, 'uid_catalog')
        ars = uc(UID=aruid)
        if not ars or len(ars) != 1:
            return []

        ar = ars[0].getObject();
        wf = getToolByName(ar, 'portal_workflow')
        allowed_states = ['verified', 'published']
        # Publish/Republish allowed?
        if wf.getInfoFor(ar, 'review_state') not in allowed_states:
            # Pre-publish allowed?
            if not ar.getAnalyses(review_state=allowed_states):
                return []

        # HTML written to debug file
        debug_mode = App.config.getConfiguration().debug_mode
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".html")
            logger.debug("Writing HTML for %s to %s" % (ar.Title(), tmp_fn))
            open(tmp_fn, "wb").write(results_html)

        # Create the pdf report (will always be attached to the AR)
        # we must supply the file ourself so that createPdf leaves it alone.
        pdf_fn = tempfile.mktemp(suffix=".pdf")
        pdf_report = createPdf(htmlreport=results_html, outfile=pdf_fn)

        # PDF written to debug file
        if debug_mode:
            logger.debug("Writing PDF for %s to %s" % (ar.Title(), pdf_fn))
        else:
            os.remove(pdf_fn)

        recipients = []
        contact = ar.getContact()
        lab = ar.bika_setup.laboratory
        if pdf_report:
            if contact:
                recipients = [{
                    'UID': contact.UID(),
                    'Username': to_utf8(contact.getUsername()),
                    'Fullname': to_utf8(contact.getFullname()),
                    'EmailAddress': to_utf8(contact.getEmailAddress()),
                    'PublicationModes': contact.getPublicationPreference()
                }]
            reportid = ar.generateUniqueId('ARReport')
            report = _createObjectByType("ARReport", ar, reportid)
            report.edit(
                AnalysisRequest=ar.UID(),
                Pdf=pdf_report,
                Html=results_html,
                Recipients=recipients
            )
            report.unmarkCreationFlag()
            renameAfterCreation(report)

            # Set status to prepublished/published/republished
            status = wf.getInfoFor(ar, 'review_state')
            transitions = {'verified': 'publish',
                           'published' : 'republish'}
            transition = transitions.get(status, 'prepublish')
            try:
                wf.doActionFor(ar, transition)
            except WorkflowException:
                pass

            # compose and send email.
            # The managers of the departments for which the current AR has
            # at least one AS must receive always the pdf report by email.
            # https://github.com/bikalabs/Bika-LIMS/issues/1028
            mime_msg = MIMEMultipart('related')
            mime_msg['Subject'] = self.get_mail_subject(ar)[0]
            mime_msg['From'] = formataddr(
                (encode_header(lab.getName()), lab.getEmailAddress()))
            mime_msg.preamble = 'This is a multi-part MIME message.'
            msg_txt = MIMEText(results_html, _subtype='html')
            mime_msg.attach(msg_txt)

            to = []
            mngrs = ar.getResponsible()
            for mngrid in mngrs['ids']:
                name = mngrs['dict'][mngrid].get('name', '')
                email = mngrs['dict'][mngrid].get('email', '')
                if (email != ''):
                    to.append(formataddr((encode_header(name), email)))

            if len(to) > 0:
                # Send the email to the managers
                mime_msg['To'] = ','.join(to)
                attachPdf(mime_msg, pdf_report, ar.id)

                try:
                    host = getToolByName(ar, 'MailHost')
                    host.send(mime_msg.as_string(), immediate=True)
                except SMTPServerDisconnected as msg:
                    logger.warn("SMTPServerDisconnected: %s." % msg)
                except SMTPRecipientsRefused as msg:
                    raise WorkflowException(str(msg))

        # Send report to recipients
        recips = self.get_recipients(ar)
        for recip in recips:
            if 'email' not in recip.get('pubpref', []) \
                    or not recip.get('email', ''):
                continue

            title = encode_header(recip.get('title', ''))
            email = recip.get('email')
            formatted = formataddr((title, email))

            # Create the new mime_msg object, cause the previous one
            # has the pdf already attached
            mime_msg = MIMEMultipart('related')
            mime_msg['Subject'] = self.get_mail_subject(ar)[0]
            mime_msg['From'] = formataddr(
            (encode_header(lab.getName()), lab.getEmailAddress()))
            mime_msg.preamble = 'This is a multi-part MIME message.'
            msg_txt = MIMEText(results_html, _subtype='html')
            mime_msg.attach(msg_txt)
            mime_msg['To'] = formatted

            # Attach the pdf to the email if requested
            if pdf_report and 'pdf' in recip.get('pubpref'):
                attachPdf(mime_msg, pdf_report, ar.id)

            # For now, I will simply ignore mail send under test.
            if hasattr(self.portal, 'robotframework'):
                continue

            msg_string = mime_msg.as_string()

            # content of outgoing email written to debug file
            if debug_mode:
                tmp_fn = tempfile.mktemp(suffix=".email")
                logger.debug("Writing MIME message for %s to %s" % (ar.Title(), tmp_fn))
                open(tmp_fn, "wb").write(msg_string)

            try:
                host = getToolByName(ar, 'MailHost')
                host.send(msg_string, immediate=True)
            except SMTPServerDisconnected as msg:
                logger.warn("SMTPServerDisconnected: %s." % msg)
            except SMTPRecipientsRefused as msg:
                raise WorkflowException(str(msg))

        return [ar]
Ejemplo n.º 30
0
    def workflow_action_retract_ar(self):
        workflow = getToolByName(self.context, "portal_workflow")
        # AR should be retracted
        # Can't transition inactive ARs
        if not isActive(self.context):
            message = _("Item is inactive.")
            self.context.plone_utils.addPortalMessage(message, "info")
            self.request.response.redirect(self.context.absolute_url())
            return

        # 1. Copies the AR linking the original one and viceversa
        ar = self.context
        newar = self.cloneAR(ar)

        # 2. The old AR gets a status of 'invalid'
        workflow.doActionFor(ar, "retract_ar")

        # 3. The new AR copy opens in status 'to be verified'
        changeWorkflowState(newar, "bika_ar_workflow", "to_be_verified")

        # 4. The system immediately alerts the client contacts who ordered
        # the results, per email and SMS, that a possible mistake has been
        # picked up and is under investigation.
        # A much possible information is provided in the email, linking
        # to the AR online.
        laboratory = self.context.bika_setup.laboratory
        lab_address = "<br/>".join(laboratory.getPrintAddress())
        mime_msg = MIMEMultipart("related")
        mime_msg["Subject"] = t(
            _("Erroneus result publication from ${request_id}", mapping={"request_id": ar.getRequestID()})
        )
        mime_msg["From"] = formataddr((encode_header(laboratory.getName()), laboratory.getEmailAddress()))
        to = []
        contact = ar.getContact()
        if contact:
            to.append(formataddr((encode_header(contact.Title()), contact.getEmailAddress())))
        for cc in ar.getCCContact():
            formatted = formataddr((encode_header(cc.Title()), cc.getEmailAddress()))
            if formatted not in to:
                to.append(formatted)

        managers = self.context.portal_groups.getGroupMembers("LabManagers")
        for bcc in managers:
            user = self.portal.acl_users.getUser(bcc)
            if user:
                uemail = user.getProperty("email")
                ufull = user.getProperty("fullname")
                formatted = formataddr((encode_header(ufull), uemail))
                if formatted not in to:
                    to.append(formatted)
        mime_msg["To"] = ",".join(to)
        aranchor = "<a href='%s'>%s</a>" % (ar.absolute_url(), ar.getRequestID())
        naranchor = "<a href='%s'>%s</a>" % (newar.absolute_url(), newar.getRequestID())
        addremarks = (
            ("addremarks" in self.request and ar.getRemarks())
            and (
                "<br/><br/>"
                + _("Additional remarks:")
                + "<br/>"
                + ar.getRemarks().split("===")[1].strip()
                + "<br/><br/>"
            )
            or ""
        )
        sub_d = dict(request_link=aranchor, new_request_link=naranchor, remarks=addremarks, lab_address=lab_address)
        body = Template(
            "Some errors have been detected in the results report "
            "published from the Analysis Request $request_link. The Analysis "
            "Request $new_request_link has been created automatically and the "
            "previous has been invalidated.<br/>The possible mistake "
            "has been picked up and is under investigation.<br/><br/>"
            "$remarks $lab_address"
        ).safe_substitute(sub_d)
        msg_txt = MIMEText(safe_unicode(body).encode("utf-8"), _subtype="html")
        mime_msg.preamble = "This is a multi-part MIME message."
        mime_msg.attach(msg_txt)
        try:
            host = getToolByName(self.context, "MailHost")
            host.send(mime_msg.as_string(), immediate=True)
        except Exception as msg:
            message = _(
                "Unable to send an email to alert lab "
                "client contacts that the Analysis Request has been "
                "retracted: ${error}",
                mapping={"error": safe_unicode(msg)},
            )
            self.context.plone_utils.addPortalMessage(message, "warning")

        message = _("${items} invalidated.", mapping={"items": ar.getRequestID()})
        self.context.plone_utils.addPortalMessage(message, "warning")
        self.request.response.redirect(newar.absolute_url())
Ejemplo n.º 31
0
 def get_formatted_email(self, email_name):
     """Formats a email
     """
     return formataddr((encode_header(email_name[0]), email_name[1]))
Ejemplo n.º 32
0
    def publishFromHTML(self, aruid, results_html):
        # The AR can be published only and only if allowed
        uc = getToolByName(self.context, 'uid_catalog')
        #ars = uc(UID=aruid)
        ars = [p.getObject() for p in uc(UID=aruid)]
        if not ars or len(ars) != 1:
            return []

        ar = ars[0]
        wf = getToolByName(ar, 'portal_workflow')
        allowed_states = ['verified', 'published']
        # Publish/Republish allowed?
        if wf.getInfoFor(ar, 'review_state') not in allowed_states:
            # Pre-publish allowed?
            if not ar.getAnalyses(review_state=allowed_states):
                return []

        # HTML written to debug file
        debug_mode = App.config.getConfiguration().debug_mode
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".html")
            logger.debug("Writing HTML for %s to %s" % (ar.Title(), tmp_fn))
            open(tmp_fn, "wb").write(results_html)

        # Create the pdf report (will always be attached to the AR)
        # we must supply the file ourself so that createPdf leaves it alone.
        pdf_fn = tempfile.mktemp(suffix=".pdf")
        pdf_report = createPdf(htmlreport=results_html, outfile=pdf_fn)

        # PDF written to debug file
        if debug_mode:
            logger.debug("Writing PDF for %s to %s" % (ar.Title(), pdf_fn))
        else:
            os.remove(pdf_fn)

        recipients = []
        contact = ar.getContact()
        lab = ar.bika_setup.laboratory

        # BIKA Cannabis hack.  Create the CSV they desire here now
        #csvdata = self.create_cannabis_csv(ars)
        csvdata = self.create_metrc_csv(ars)
        pdf_fn = to_utf8(ar.getRequestID())
        if pdf_report:
            if contact:
                recipients = [{
                    'UID':
                    contact.UID(),
                    'Username':
                    to_utf8(contact.getUsername()),
                    'Fullname':
                    to_utf8(contact.getFullname()),
                    'EmailAddress':
                    to_utf8(contact.getEmailAddress()),
                    'PublicationModes':
                    contact.getPublicationPreference()
                }]
            reportid = ar.generateUniqueId('ARReport')
            report = _createObjectByType("ARReport", ar, reportid)
            report.edit(AnalysisRequest=ar.UID(),
                        Pdf=pdf_report,
                        CSV=csvdata,
                        Html=results_html,
                        Recipients=recipients)
            report.unmarkCreationFlag()
            renameAfterCreation(report)
            # Set blob properties for fields containing file data
            fld = report.getField('Pdf')
            fld.get(report).setFilename(pdf_fn + ".pdf")
            fld.get(report).setContentType('application/pdf')
            fld = report.getField('CSV')
            fld.get(report).setFilename(pdf_fn + ".csv")
            fld.get(report).setContentType('text/csv')

            # Set status to prepublished/published/republished
            status = wf.getInfoFor(ar, 'review_state')
            transitions = {'verified': 'publish', 'published': 'republish'}
            transition = transitions.get(status, 'prepublish')
            try:
                wf.doActionFor(ar, transition)
            except WorkflowException:
                pass

            # compose and send email.
            # The managers of the departments for which the current AR has
            # at least one AS must receive always the pdf report by email.
            # https://github.com/bikalabs/Bika-LIMS/issues/1028
            mime_msg = MIMEMultipart('related')
            mime_msg['Subject'] = self.get_mail_subject(ar)[0]
            mime_msg['From'] = formataddr(
                (encode_header(lab.getName()), lab.getEmailAddress()))
            mime_msg.preamble = 'This is a multi-part MIME message.'
            msg_txt = MIMEText(results_html, _subtype='html')
            mime_msg.attach(msg_txt)

            to = []
            #mngrs = ar.getResponsible()
            #for mngrid in mngrs['ids']:
            #    name = mngrs['dict'][mngrid].get('name', '')
            #    email = mngrs['dict'][mngrid].get('email', '')
            #    if (email != ''):
            #        to.append(formataddr((encode_header(name), email)))

            #if len(to) > 0:
            #    # Send the email to the managers
            #    mime_msg['To'] = ','.join(to)
            #    attachPdf(mime_msg, pdf_report, pdf_fn)

            #    # BIKA Cannabis hack.  Create the CSV they desire here now
            #    fn = pdf_fn
            #    attachCSV(mime_msg,csvdata,fn)

            #    try:
            #        host = getToolByName(ar, 'MailHost')
            #        host.send(mime_msg.as_string(), immediate=True)
            #    except SMTPServerDisconnected as msg:
            #        logger.warn("SMTPServerDisconnected: %s." % msg)
            #    except SMTPRecipientsRefused as msg:
            #        raise WorkflowException(str(msg))

        # Send report to recipients
        recips = self.get_recipients(ar)
        for recip in recips:
            if 'email' not in recip.get('pubpref', []) \
                    or not recip.get('email', ''):
                continue

            title = encode_header(recip.get('title', ''))
            email = recip.get('email')
            formatted = formataddr((title, email))

            # Create the new mime_msg object, cause the previous one
            # has the pdf already attached
            mime_msg = MIMEMultipart('related')
            mime_msg['Subject'] = self.get_mail_subject(ar)[0]
            mime_msg['From'] = formataddr(
                (encode_header(lab.getName()), lab.getEmailAddress()))
            mime_msg.preamble = 'This is a multi-part MIME message.'
            msg_txt = MIMEText(results_html, _subtype='html')
            mime_msg.attach(msg_txt)
            mime_msg['To'] = formatted

            # Attach the pdf to the email if requested
            if pdf_report and 'pdf' in recip.get('pubpref'):
                attachPdf(mime_msg, pdf_report, pdf_fn)
                # BIKA Cannabis hack.  Create the CSV they desire here now
                fn = pdf_fn
                attachCSV(mime_msg, csvdata, fn)

            # For now, I will simply ignore mail send under test.
            if hasattr(self.portal, 'robotframework'):
                continue

            msg_string = mime_msg.as_string()

            # content of outgoing email written to debug file
            if debug_mode:
                tmp_fn = tempfile.mktemp(suffix=".email")
                logger.debug("Writing MIME message for %s to %s" %
                             (ar.Title(), tmp_fn))
                open(tmp_fn, "wb").write(msg_string)

            try:
                host = getToolByName(ar, 'MailHost')
                host.send(msg_string, immediate=True)
            except SMTPServerDisconnected as msg:
                logger.warn("SMTPServerDisconnected: %s." % msg)
            except SMTPRecipientsRefused as msg:
                raise WorkflowException(str(msg))

        # Save file on the filesystem
        folder = os.environ.get('COAs_FOLDER', '')
        if len(folder) != 0:
            client_path = '{}/{}/'.format(folder, ar.getClientID())
            if not os.path.exists(client_path):
                os.makedirs(client_path)

            today = self.ulocalized_time(DateTime(), long_format=0)
            today_path = '{}{}/'.format(client_path, today)
            if not os.path.exists(today_path):
                os.makedirs(today_path)

            fname = '{}{}.pdf'.format(today_path, pdf_fn)
            f = open(fname, 'w')
            f.write(pdf_report)
            f.close()

            csvname = '{}{}.csv'.format(today_path, pdf_fn)
            fcsv = open(csvname, 'w')
            fcsv.write(csvdata)
            fcsv.close()

        return [ar]
Ejemplo n.º 33
0
    def workflow_action_retract_ar(self):
        workflow = getToolByName(self.context, 'portal_workflow')
        # AR should be retracted
        # Can't transition inactive ARs
        if not isActive(self.context):
            message = _('Item is inactive.')
            self.context.plone_utils.addPortalMessage(message, 'info')
            self.request.response.redirect(self.context.absolute_url())
            return

        # 1. Copies the AR linking the original one and viceversa
        ar = self.context
        newar = self.cloneAR(ar)

        # 2. The old AR gets a status of 'invalid'
        workflow.doActionFor(ar, 'retract_ar')

        # 3. The new AR copy opens in status 'to be verified'
        changeWorkflowState(newar, 'bika_ar_workflow', 'to_be_verified')

        # 4. The system immediately alerts the client contacts who ordered
        # the results, per email and SMS, that a possible mistake has been
        # picked up and is under investigation.
        # A much possible information is provided in the email, linking
        # to the AR online.
        laboratory = self.context.bika_setup.laboratory
        lab_address = "<br/>".join(laboratory.getPrintAddress())
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = t(_("Erroneus result publication from ${request_id}",
                                mapping={"request_id": ar.getRequestID()}))
        mime_msg['From'] = formataddr(
            (encode_header(laboratory.getName()),
             laboratory.getEmailAddress()))
        to = []
        contact = ar.getContact()
        if contact:
            to.append(formataddr((encode_header(contact.Title()),
                                   contact.getEmailAddress())))
        for cc in ar.getCCContact():
            formatted = formataddr((encode_header(cc.Title()),
                                   cc.getEmailAddress()))
            if formatted not in to:
                to.append(formatted)

        managers = self.context.portal_groups.getGroupMembers('LabManagers')
        for bcc in managers:
            user = self.portal.acl_users.getUser(bcc)
            if user:
                uemail = user.getProperty('email')
                ufull = user.getProperty('fullname')
                formatted = formataddr((encode_header(ufull), uemail))
                if formatted not in to:
                    to.append(formatted)
        mime_msg['To'] = ','.join(to)
        aranchor = "<a href='%s'>%s</a>" % (ar.absolute_url(),
                                            ar.getRequestID())
        naranchor = "<a href='%s'>%s</a>" % (newar.absolute_url(),
                                             newar.getRequestID())
        addremarks = ('addremarks' in self.request
                      and ar.getRemarks()) \
                    and ("<br/><br/>"
                         + _("Additional remarks:")
                         + "<br/>"
                         + ar.getRemarks().split("===")[1].strip()
                         + "<br/><br/>") \
                    or ''

        body = _("Some errors have been detected in the results report "
                 "published from the Analysis Request ${request_link}. The Analysis "
                 "Request ${new_request_link} has been created automatically and the "
                 "previous has been invalidated.<br/>The possible mistake "
                 "has been picked up and is under investigation.<br/><br/>"
                 "${remarks}${lab_address}",
                 mapping={"request_link":aranchor,
                          "new_request_link":naranchor,
                          "remarks": addremarks,
                          "lab_address": lab_address})
        msg_txt = MIMEText(safe_unicode(body).encode('utf-8'),
                           _subtype='html')
        mime_msg.preamble = 'This is a multi-part MIME message.'
        mime_msg.attach(msg_txt)
        try:
            host = getToolByName(self.context, 'MailHost')
            host.send(mime_msg.as_string(), immediate=True)
        except Exception as msg:
            message = _('Unable to send an email to alert lab '
                        'client contacts that the Analysis Request has been '
                        'retracted: ${error}',
                        mapping={'error': safe_unicode(msg)})
            self.context.plone_utils.addPortalMessage(message, 'warning')

        message = _('${items} invalidated.',
                    mapping={'items': ar.getRequestID()})
        self.context.plone_utils.addPortalMessage(message, 'warning')
        self.request.response.redirect(newar.absolute_url())
Ejemplo n.º 34
0
    def publishFromHTML(self, prouid, results_html):

        uc = getToolByName(self.context, 'uid_catalog')
        pros = uc(UID=prouid)
        if not pros or len(pros) != 1:
            return []

        pro = pros[0].getObject();
        
        # HTML written to debug file
        debug_mode = App.config.getConfiguration().debug_mode
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".html")
            logger.debug("Writing HTML for %s to %s" % (pro.Title(), tmp_fn))
            open(tmp_fn, "wb").write(results_html)

        # Create the pdf report (will always be attached to the Order)
        # we must supply the file ourself so that createPdf leaves it alone.
        # This version replaces 'attachment' links; probably not required,
        # so it's repeated below, without these localise_images.
        # cleanup, results_html_for_pdf = self.localise_images(results_html)
        # pdf_fn = tempfile.mktemp(suffix=".pdf")
        # pdf_report = createPdf(htmlreport=results_html_for_pdf, outfile=pdf_fn)
        # for fn in cleanup:
        #     os.remove(fn)

        
        pdf_fn = tempfile.mktemp(suffix=".pdf")
        pdf_report = createPdf(htmlreport=results_html, outfile=pdf_fn)

        # PDF written to debug file
        if debug_mode:
            logger.debug("Writing PDF for %s to %s" % (pro.Title(), pdf_fn))
        else:
            os.remove(pdf_fn)

        recipients = []
        

        # Send report to supplier
        supplier_data = self._supplier_data(pro)
        title = encode_header(supplier_data.get('title', ''))
        email = supplier_data.get('email')
        formatted = formataddr((title, email))

        # Create the new mime_msg object
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = self.get_mail_subject(pro)
        """
        	Edit this to change the From address
        	mime_msg['From'] = formataddr(
        	(encode_header(lab.getName()), lab.getEmailAddress()))
        """
        mime_msg['From'] = formataddr(("BIKA IMM", "*****@*****.**"))
        mime_msg.preamble = 'This is a multi-part MIME message.'
        msg_txt = MIMEText(results_html, _subtype='html')
        mime_msg.attach(msg_txt)
        mime_msg['To'] = formatted

        # Attach the pdf to the email if requested
        if pdf_report:
            attachPdf(mime_msg, pdf_report, pdf_fn)

        msg_string = mime_msg.as_string()

        # content of outgoing email written to debug file
        if debug_mode:
            tmp_fn = tempfile.mktemp(suffix=".email")
            logger.debug("Writing MIME message for %s to %s" % (pro.Title(), tmp_fn))
            open(tmp_fn, "wb").write(msg_string)

        try:
            host = getToolByName(pro, 'MailHost')
            host.send(msg_string, immediate=True)
        except SMTPServerDisconnected as msg:
            logger.warn("SMTPServerDisconnected: %s." % msg)
        except SMTPRecipientsRefused as msg:
            raise WorkflowException(str(msg))

        pro.setDateDispatched(DateTime())
        return [pro]
Ejemplo n.º 35
0
    def __call__(self):

        rc = getToolByName(self.context, REFERENCE_CATALOG)
        workflow = getToolByName(self.context, 'portal_workflow')

        laboratory = self.context.bika_setup.laboratory
        BatchEmail = self.context.bika_setup.getBatchEmail()
        BatchFax = self.context.bika_setup.getBatchFax()

        # group analysis requests by contact
        ARs_by_contact = {}
        for ar in self.analysis_requests:
            contact_uid = ar.getContact().UID()
            if contact_uid not in ARs_by_contact:
                ARs_by_contact[contact_uid] = []
            ARs_by_contact[contact_uid].append(ar)

        for contact_uid, ars in ARs_by_contact.items():
            ars.sort()
            self.contact = ars[0].getContact()
            self.pub_pref = self.contact.getPublicationPreference()
            batch_size = 'email' in self.pub_pref and BatchEmail or \
                         'fax' in self.pub_pref and BatchFax or 1

            # send batches of ARs to each contact
            for b in range(0, len(ars), batch_size):
                self.batch = ars[b:b+batch_size]
                self.any_accredited = False
                self.any_drymatter = False
                # get all services from all requests in this batch into a
                # dictionary:
                #   {'Point Of Capture': {'Category': [service,service,...]}}
                self.services = {}
                for ar in self.batch:
                    if ar.getReportDryMatter():
                        self.any_drymatter = True
                    states = ("verified", "published")
                    for analysis in ar.getAnalyses(full_objects=True,
                                                   review_state=states):
                        service = analysis.getService()
                        poc = POINTS_OF_CAPTURE.getValue(service.getPointOfCapture())
                        cat = service.getCategoryTitle()
                        if poc not in self.services:
                            self.services[poc] = {}
                        if cat not in self.services[poc]:
                            self.services[poc][cat] = []
                        self.services[poc][cat].append(service)
                        if (service.getAccredited()):
                            self.any_accredited = True

                # compose and send email
                if 'email' in self.pub_pref:

                    # render template to utf-8
                    ar_results = self.ar_results().encode("utf-8")

                    # XXX
                    ar_debug_name = '%s_%s.html' % \
                        (self.analysis_requests[0].Title(), self.action)
                    open(join(Globals.INSTANCE_HOME,'var', ar_debug_name),
                                "w").write(ar_results)

                    mime_msg = MIMEMultipart('related')
                    mime_msg['Subject'] = self.get_mail_subject()
                    mime_msg['From'] = formataddr(
                        (encode_header(laboratory.getName()),
                         laboratory.getEmailAddress()))
                    mime_msg['To'] = formataddr(
                        (encode_header(self.contact.getFullname()),
                         self.contact.getEmailAddress()))
                    mime_msg.preamble = 'This is a multi-part MIME message.'
                    msg_txt = MIMEText(ar_results, _subtype='html')
                    mime_msg.attach(msg_txt)

                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except SMTPRecipientsRefused, msg:
                        raise WorkflowException(str(msg))
                    if self.action == 'publish':
                        for ar in self.batch:
                            try:
                                workflow.doActionFor(ar, 'publish')
                            except WorkflowException:
                                pass
                else:
                    raise Exception, "XXX pub_pref %s" % self.pub_pref
Ejemplo n.º 36
0
    def publishFromHTML(self, ar_uids, results_html):
        """ar_uids can be a single UID or a list of AR uids.  The resulting
        ARs will be published together (ie, sent as a single outbound email)
        and the entire report will be saved in each AR's published-results
        tab.
        """
        debug_mode = App.config.getConfiguration().debug_mode
        wf = getToolByName(self.context, 'portal_workflow')

        # The AR can be published only and only if allowed
        uc = getToolByName(self.context, 'uid_catalog')
        ars = [p.getObject() for p in uc(UID=ar_uids)]
        if not ars:
            return []

        results_html = self.localize_images(results_html)
        # Create the pdf report for the supplied HTML.
        open('/tmp/2499.html', 'w').write(results_html)
        pdf_report = createPdf(results_html, False)
        # PDF written to debug file?
        if debug_mode:
            pdf_fn = tempfile.mktemp(suffix=".pdf")
            logger.info("Writing PDF for {} to {}".format(
                ', '.join([ar.Title() for ar in ars]), pdf_fn))
            open(pdf_fn, 'wb').write(pdf_report)

        for ar in ars:
            # Generate in each relevant AR, a new ARReport
            reportid = ar.generateUniqueId('ARReport')
            report = _createObjectByType("ARReport", ar, reportid)
            report.edit(
                AnalysisRequest=ar.UID(),
                Pdf=pdf_report,
                Html=results_html,
            )
            report.unmarkCreationFlag()
            renameAfterCreation(report)
            # Modify the workflow state of each AR that's been published
            status = wf.getInfoFor(ar, 'review_state')
            transitions = {'verified': 'publish', 'published': 'republish'}
            transition = transitions.get(status, 'prepublish')
            try:
                wf.doActionFor(ar, transition)
            except WorkflowException:
                pass

        # compose and send email.
        # The managers of the departments for which the current AR has
        # at least one AS must receive always the pdf report by email.
        # https://github.com/bikalabs/Bika-LIMS/issues/1028
        lab = ars[0].bika_setup.laboratory
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = "Published results for %s" % \
                              ",".join([ar.Title() for ar in ars])
        mime_msg['From'] = formataddr(
            (encode_header(lab.getName()), lab.getEmailAddress()))
        mime_msg.preamble = 'This is a multi-part MIME message.'
        msg_txt = MIMEText(results_html, _subtype='html')
        mime_msg.attach(msg_txt)

        to = []
        to_emails = []

        mngrs = []
        for ar in ars:
            resp = ar.getResponsible()
            if 'dict' in resp and resp['dict']:
                for mngrid, mngr in resp['dict'].items():
                    if mngr['email'] not in [m['email'] for m in mngrs]:
                        mngrs.append(mngr)
        for mngr in mngrs:
            name = mngr['name']
            email = mngr['email']
            to.append(formataddr((encode_header(name), email)))

        # Send report to recipients
        for ar in ars:
            recips = self.get_recipients(ar)
            for recip in recips:
                if 'email' not in recip.get('pubpref', []) \
                        or not recip.get('email', ''):
                    continue
                title = encode_header(recip.get('title', ''))
                email = recip.get('email')
                if email not in to_emails:
                    to.append(formataddr((title, email)))
                    to_emails.append(email)

        # Create the new mime_msg object, cause the previous one
        # has the pdf already attached
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = "Published results for %s" % \
                              ",".join([ar.Title() for ar in ars])
        mime_msg['From'] = formataddr(
            (encode_header(lab.getName()), lab.getEmailAddress()))
        mime_msg.preamble = 'This is a multi-part MIME message.'
        msg_txt = MIMEText(results_html, _subtype='html')
        mime_msg.attach(msg_txt)
        mime_msg['To'] = ",".join(to)

        # Attach the pdf to the email
        fn = "_".join([ar.Title() for ar in ars])
        attachPdf(mime_msg, pdf_report, fn)

        # ALS hack.  Create the CSV they desire here now
        csvdata = self.create_als_csv(ars)
        # Attach to email
        part = MIMEBase('text', "csv")
        fn = self.current_certificate_number()
        part.add_header('Content-Disposition',
                        'attachment; filename="{}.csv"'.format(fn))
        part.set_payload(csvdata)
        mime_msg.attach(part)

        msg_string = mime_msg.as_string()

        try:
            host = getToolByName(ars[0], 'MailHost')
            host.send(msg_string, immediate=True)
        except SMTPServerDisconnected as msg:
            logger.warn("SMTPServerDisconnected: %s." % msg)
        except SMTPRecipientsRefused as msg:
            raise WorkflowException(str(msg))

        return ars
Ejemplo n.º 37
0
    def __call__(self):

        rc = getToolByName(self.context, REFERENCE_CATALOG)
        workflow = getToolByName(self.context, "portal_workflow")

        BatchEmail = self.context.bika_setup.getBatchEmail()

        username = self.context.portal_membership.getAuthenticatedMember().getUserName()
        self.reporter = self.user_fullname(username)
        self.reporter_email = self.user_email(username)

        # signature image
        self.reporter_signature = ""
        c = [x for x in self.bika_setup_catalog(portal_type="LabContact") if x.getObject().getUsername() == username]
        if c:
            sf = c[0].getObject().getSignature()
            if sf:
                self.reporter_signature = sf.absolute_url() + "/Signature"

        # lab address
        self.laboratory = laboratory = self.context.bika_setup.laboratory
        self.lab_address = "<br/>".join(laboratory.getPrintAddress())

        # group/publish analysis requests by contact
        ARs_by_contact = {}
        for ar in self.analysis_requests:
            contact_uid = ar.getContact().UID()
            if contact_uid not in ARs_by_contact:
                ARs_by_contact[contact_uid] = []
            ARs_by_contact[contact_uid].append(ar)

        for contact_uid, ars in ARs_by_contact.items():
            ars.sort()
            self.contact = ars[0].getContact()
            self.pub_pref = self.contact.getPublicationPreference()
            batch_size = "email" in self.pub_pref and BatchEmail or 5

            # client address
            self.client = ars[0].aq_parent
            self.client_address = "<br/>".join(self.client.getPrintAddress())

            self.Footer = self.context.bika_setup.getResultFooter()

            # send batches of ARs to each contact
            for b in range(0, len(ars), batch_size):
                self.batch = ars[b : b + batch_size]
                self.any_accredited = False
                self.any_drymatter = False
                # get all services from all requests in this batch into a
                # dictionary:
                #   {'Point Of Capture': {'Category': [service,service,...]}}
                self.services = {}

                out_fn = "_".join([ar.Title() for ar in self.batch])

                for ar in self.batch:
                    if ar.getReportDryMatter():
                        self.any_drymatter = True
                    states = ("verified", "published")
                    for analysis in ar.getAnalyses(full_objects=True, review_state=states):
                        service = analysis.getService()
                        poc = POINTS_OF_CAPTURE.getValue(service.getPointOfCapture())
                        cat = service.getCategoryTitle()
                        if poc not in self.services:
                            self.services[poc] = {}
                        if cat not in self.services[poc]:
                            self.services[poc][cat] = []
                        if service not in self.services[poc][cat]:
                            self.services[poc][cat].append(service)
                        if service.getAccredited():
                            self.any_accredited = True

                # compose and send email
                if "email" in self.pub_pref:

                    # render template
                    ar_results = self.ar_results()
                    ar_results = safe_unicode(ar_results).encode("utf-8")
                    ar_results = self.escape(ar_results)

                    debug_mode = App.config.getConfiguration().debug_mode
                    if debug_mode:
                        open(join(Globals.INSTANCE_HOME, "var", out_fn + ".html"), "w").write(ar_results)

                    pisa.showLogging()
                    ramdisk = StringIO()
                    pdf = pisa.CreatePDF(ar_results, ramdisk)
                    pdf_data = ramdisk.getvalue()
                    ramdisk.close()

                    if debug_mode:
                        open(join(Globals.INSTANCE_HOME, "var", out_fn + ".pdf"), "wb").write(pdf_data)

                    mime_msg = MIMEMultipart("related")
                    mime_msg["Subject"] = self.get_mail_subject()
                    mime_msg["From"] = formataddr((encode_header(laboratory.getName()), laboratory.getEmailAddress()))
                    mime_msg["To"] = formataddr(
                        (encode_header(self.contact.getFullname()), self.contact.getEmailAddress())
                    )
                    mime_msg.preamble = "This is a multi-part MIME message."
                    msg_txt = MIMEText(ar_results, _subtype="html")
                    mime_msg.attach(msg_txt)
                    if not pdf.err:
                        part = MIMEBase("application", "application/pdf")
                        part.add_header("Content-Disposition", 'attachment; filename="%s.pdf"' % out_fn)
                        part.set_payload(pdf_data)
                        Encoders.encode_base64(part)
                        mime_msg.attach(part)

                    try:
                        host = getToolByName(self.context, "MailHost")
                        host.send(mime_msg.as_string(), immediate=True)
                    except SMTPServerDisconnected, msg:
                        if not debug_mode:
                            raise SMTPServerDisconnected(msg)
                    except SMTPRecipientsRefused, msg:
                        raise WorkflowException(str(msg))

                    if self.action == "publish":
                        for ar in self.batch:
                            try:
                                workflow.doActionFor(ar, "publish")
                            except WorkflowException:
                                pass

                ##                    if not pdf.err:
                ##                        setheader = self.request.RESPONSE.setHeader
                ##                        setheader('Content-Type', 'application/pdf')
                ##                        setheader("Content-Disposition", "attachment;filename=\"%s.pdf\"" % out_fn)
                ##                        self.request.RESPONSE.write(pdf_data)

                else:
                    raise Exception, "XXX pub_pref %s" % self.pub_pref
Ejemplo n.º 38
0
    def __call__(self):
        # Do generic bika.lims stuff
        _AnalysisRequestWorkflowAction.__call__(self)
        # Do bika-health specific actions when submit
        action = _AnalysisRequestWorkflowAction._get_form_workflow_action(self)
        addPortalMessage = self.context.plone_utils.addPortalMessage
        if action[0] == 'submit' and isActive(self.context):
            inpanicanalyses = []
            workflow = getToolByName(self.context, 'portal_workflow')
            translate = self.context.translate
            rc = getToolByName(self.context, REFERENCE_CATALOG)
            uc = getToolByName(self.context, 'uid_catalog')
            # retrieve the results from database and check if
            # the values are exceeding panic levels
            alerts = {}
            for uid in self.request.form.get('Result', [{}])[0].keys():
                analysis = rc.lookupObject(uid)
                analysis = analysis.getObject() if hasattr(analysis, 'getObject') else analysis
                if not analysis:
                    continue
                astate = workflow.getInfoFor(analysis, 'review_state')
                if astate == 'retracted':
                    continue
                alerts.update(ResultOutOfRange(analysis)())
            if alerts:
                message = translate(_('Some results exceeded the '
                                      'panic levels that may '
                                      'indicate an imminent '
                                      'life-threatening condition'
                                      ))
                addPortalMessage(message, 'warning')
                self.request.response.redirect(self.context.absolute_url())

                # If panic levels alert email enabled, send an email to
                # labmanagers
                bs = self.context.bika_setup
                if hasattr(bs, 'getEnablePanicAlert') \
                        and bs.getEnablePanicAlert():
                    laboratory = self.context.bika_setup.laboratory
                    lab_address = "<br/>".join(laboratory.getPrintAddress())
                    managers = self.context.portal_groups.getGroupMembers('LabManagers')
                    mime_msg = MIMEMultipart('related')
                    mime_msg['Subject'] = _("Panic alert")
                    mime_msg['From'] = formataddr(
                        (encode_header(laboratory.getName()),
                         laboratory.getEmailAddress()))
                    to = []
                    for manager in managers:
                        user = self.portal.acl_users.getUser(manager)
                        uemail = user.getProperty('email')
                        ufull = user.getProperty('fullname')
                        to.append(formataddr((encode_header(ufull), uemail)))
                    mime_msg['To'] = ','.join(to)
                    strans = []
                    ars = {}
                    for analysis_uid, alertlist in alerts:
                        analysis = uc(analysis_uid).getObject()
                        for alert in alertlist:
                            ars[analysis.aq_parent.Title()] = 1
                            strans.append("- {0}, {1}: {2}".format(
                                          analysis.Title(),
                                          translate(_("Result")),
                                          analysis.getResult()))
                    ars = ", ".join(ars.keys())
                    stran = "<br/>".join(strans)
                    text = translate(_(
                        "Some results from ${items} exceeded the panic levels "
                        "that may indicate an imminent life-threatening "
                        "condition: <br/><br/>{analysisresults}<br/><br/>"
                        "<b>Please, check the Analysis Request if you "
                        "want to re-test the analysis or immediately "
                        "alert the client.</b><br/><br/>{lab_address}",
                        mapping={'items': ars,
                                 'analysisresults': stran,
                                 'lab_address': lab_address}))
                    msg_txt = MIMEText(safe_unicode(text).encode('utf-8'),
                                       _subtype='html')
                    mime_msg.preamble = 'This is a multi-part MIME message.'
                    mime_msg.attach(msg_txt)
                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except Exception as msg:
                        ar = inpanicanalyses[0].getRequestID()
                        logger.error("Panic level email %s: %s" %
                                     (ar, str(msg)))
                        message = translate(
                            _('Unable to send an email to alert lab '
                              'managers that some analyses exceeded the '
                              'panic levels') + (": %s" % str(msg)))
                        addPortalMessage(message, 'warning')
Ejemplo n.º 39
0
    def __call__(self):
        # Do generic bika.lims stuff
        BaseClass.__call__(self)
        # Do bika-health specific actions when submit
        action = BaseClass._get_form_workflow_action(self)
        addPortalMessage = self.context.plone_utils.addPortalMessage
        if action[0] == 'submit' and isActive(self.context):
            inpanicanalyses = []
            workflow = getToolByName(self.context, 'portal_workflow')
            translate = self.context.translate
            rc = getToolByName(self.context, REFERENCE_CATALOG)
            uc = getToolByName(self.context, 'uid_catalog')
            # retrieve the results from database and check if
            # the values are exceeding panic levels
            alerts = {}
            for uid in self.request.form.get('Result', [{}])[0].keys():
                analysis = rc.lookupObject(uid)
                analysis = analysis.getObject() if hasattr(analysis, 'getObject') else analysis
                if not analysis:
                    continue
                astate = workflow.getInfoFor(analysis, 'review_state')
                if astate == 'retracted':
                    continue
                alerts.update(ResultOutOfRange(analysis)())
            if alerts:
                message = translate(_('Some results exceeded the '
                                      'panic levels that may '
                                      'indicate an imminent '
                                      'life-threatening condition'
                                      ))
                addPortalMessage(message, 'warning')
                self.request.response.redirect(self.context.absolute_url())

                # If panic levels alert email enabled, send an email to
                # labmanagers
                bs = self.context.bika_setup
                if hasattr(bs, 'getEnablePanicAlert') \
                        and bs.getEnablePanicAlert():
                    laboratory = self.context.bika_setup.laboratory
                    lab_address = "<br/>".join(laboratory.getPrintAddress())
                    managers = self.context.portal_groups.getGroupMembers('LabManagers')
                    mime_msg = MIMEMultipart('related')
                    mime_msg['Subject'] = _("Panic alert")
                    mime_msg['From'] = formataddr(
                        (encode_header(laboratory.getName()),
                         laboratory.getEmailAddress()))
                    to = []
                    for manager in managers:
                        user = self.portal.acl_users.getUser(manager)
                        uemail = user.getProperty('email')
                        ufull = user.getProperty('fullname')
                        to.append(formataddr((encode_header(ufull), uemail)))
                    mime_msg['To'] = ','.join(to)
                    strans = []
                    ars = {}
                    for analysis_uid, alertlist in alerts:
                        analysis = uc(analysis_uid).getObject()
                        for alert in alertlist:
                            ars[analysis.aq_parent.Title()] = 1
                            strans.append("- {0}, {1}: {2}".format(
                                          analysis.getService().Title(),
                                          translate(_("Result")),
                                          analysis.getResult()))
                    ars = ", ".join(ars.keys())
                    stran = "<br/>".join(strans)
                    text = translate(_(
                        "Some results from ${items} exceeded the panic levels "
                        "that may indicate an imminent life-threatening "
                        "condition: <br/><br/>{analysisresults}<br/><br/>"
                        "<b>Please, check the Analysis Request if you "
                        "want to re-test the analysis or immediately "
                        "alert the client.</b><br/><br/>{lab_address}",
                        mapping={'items': ars,
                                 'analysisresults': stran,
                                 'lab_address': lab_address}))
                    msg_txt = MIMEText(safe_unicode(text).encode('utf-8'),
                                       _subtype='html')
                    mime_msg.preamble = 'This is a multi-part MIME message.'
                    mime_msg.attach(msg_txt)
                    try:
                        host = getToolByName(self.context, 'MailHost')
                        host.send(mime_msg.as_string(), immediate=True)
                    except Exception as msg:
                        ar = inpanicanalyses[0].getRequestID()
                        logger.error("Panic level email %s: %s" %
                                     (ar, str(msg)))
                        message = translate(
                            _('Unable to send an email to alert lab '
                              'managers that some analyses exceeded the '
                              'panic levels') + (": %s" % str(msg)))
                        addPortalMessage(message, 'warning')
Ejemplo n.º 40
0
    def notify_ar_retract(self, ar, newar):
        bika_setup = api.get_bika_setup()
        laboratory = bika_setup.laboratory
        lab_address = "<br/>".join(laboratory.getPrintAddress())
        mime_msg = MIMEMultipart('related')
        mime_msg['Subject'] = t(_("Erroneus result publication from ${request_id}",
                                mapping={"request_id": ar.getRequestID()}))
        mime_msg['From'] = formataddr(
            (encode_header(laboratory.getName()),
             laboratory.getEmailAddress()))
        to = []
        contact = ar.getContact()
        if contact:
            to.append(formataddr((encode_header(contact.Title()),
                                  contact.getEmailAddress())))
        for cc in ar.getCCContact():
            formatted = formataddr((encode_header(cc.Title()),
                                   cc.getEmailAddress()))
            if formatted not in to:
                to.append(formatted)

        managers = self.context.portal_groups.getGroupMembers('LabManagers')
        for bcc in managers:
            user = self.portal.acl_users.getUser(bcc)
            if user:
                uemail = user.getProperty('email')
                ufull = user.getProperty('fullname')
                formatted = formataddr((encode_header(ufull), uemail))
                if formatted not in to:
                    to.append(formatted)
        mime_msg['To'] = ','.join(to)
        aranchor = "<a href='%s'>%s</a>" % (ar.absolute_url(),
                                            ar.getRequestID())
        naranchor = "<a href='%s'>%s</a>" % (newar.absolute_url(),
                                             newar.getRequestID())
        addremarks = ('addremarks' in self.request and ar.getRemarks()) and ("<br/><br/>" + _("Additional remarks:") +
                                                                             "<br/>" + ar.getRemarks().split("===")[1].strip() +
                                                                             "<br/><br/>") or ''
        sub_d = dict(request_link=aranchor,
                     new_request_link=naranchor,
                     remarks=addremarks,
                     lab_address=lab_address)
        body = Template("Some errors have been detected in the results report "
                        "published from the Analysis Request $request_link. The Analysis "
                        "Request $new_request_link has been created automatically and the "
                        "previous has been invalidated.<br/>The possible mistake "
                        "has been picked up and is under investigation.<br/><br/>"
                        "$remarks $lab_address").safe_substitute(sub_d)
        msg_txt = MIMEText(safe_unicode(body).encode('utf-8'),
                           _subtype='html')
        mime_msg.preamble = 'This is a multi-part MIME message.'
        mime_msg.attach(msg_txt)
        try:
            host = getToolByName(self.context, 'MailHost')
            host.send(mime_msg.as_string(), immediate=True)
        except Exception as msg:
            message = _('Unable to send an email to alert lab '
                        'client contacts that the Analysis Request has been '
                        'retracted: ${error}',
                        mapping={'error': safe_unicode(msg)})
            self.context.plone_utils.addPortalMessage(message, 'warning')