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()
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()
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()
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')
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')
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)
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
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")
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))
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)
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)
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)
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)
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))
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)
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)
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)
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())
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
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')
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
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
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]
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]
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]
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
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]
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())
def get_formatted_email(self, email_name): """Formats a email """ return formataddr((encode_header(email_name[0]), email_name[1]))
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]
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())
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]
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
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
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
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')
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')
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')