def pdf(self): cssfn = resource_filename("bika.uw", "browser/css/batch-pdf.css") pdf_data = createPdf(t(self.pdf_wrapper()), css=cssfn) setheader = self.request.RESPONSE.setHeader setheader('Content-Length', len(pdf_data)) setheader('Content-Type', 'application/pdf') fn = self.context.Title() + ".pdf" setheader('Content-Disposition', 'inline; filename="{0}"'.format(fn)) self.request.RESPONSE.write(pdf_data)
def pdf_from_post(self): """Returns a pdf stream with the stickers """ html = self.request.form.get("html") style = self.request.form.get("style") reporthtml = "<html><head>{0}</head><body>{1}</body></html>" reporthtml = reporthtml.format(style, html) reporthtml = safe_unicode(reporthtml).encode("utf-8") pdf_fn = tempfile.mktemp(suffix=".pdf") pdf_file = createPdf(htmlreport=reporthtml, outfile=pdf_fn) return pdf_file
def pdf_from_post(self): """Returns a pdf stream with the stickers """ html = self.request.form.get('html') style = self.request.form.get('style') reporthtml = '<html><head>{0}</head><body>{1}</body></html>' reporthtml = reporthtml.format(style, html) reporthtml = safe_unicode(reporthtml).encode('utf-8') pdf_fn = tempfile.mktemp(suffix='.pdf') pdf_file = createPdf(htmlreport=reporthtml, outfile=pdf_fn) return pdf_file
def generate_delivery_pdf(context, ars_or_samples): if not ars_or_samples: logger.warn("No Analysis Requests or Samples provided") return if ISample.providedBy(ars_or_samples) or \ IAnalysisRequest.providedBy(ars_or_samples): return generate_delivery_pdf(context, [ars_or_samples]) if not isinstance(ars_or_samples, list): logger.warn("Type not supported: {}".format(repr(ars_or_samples))) return html = DeliveryFormPdf(context, context.REQUEST, analysis_requests=ars_or_samples).template() html = safe_unicode(html).encode("utf-8") filename = "delivery" pdf_fn = tempfile.mktemp(suffix=".pdf") pdf = createPdf(htmlreport=html, outfile=pdf_fn) if not pdf: ar_ids = map(lambda ar: ar.id, ars_or_samples) logger.warn( "Unable to generate the PDF of delivery form for {}".format( ' '.join(ar_ids))) return None def _attach_to_ar(pdf, ar_brain_or_obj): ar = api.get_object(ar_brain_or_obj) attid = ar.aq_parent.generateUniqueId('Attachment') att = _createObjectByType("Attachment", ar.aq_parent, attid) att.setAttachmentFile(open(pdf_fn)) # Awkward workaround to rename the file attf = att.getAttachmentFile() attf.filename = '%s.pdf' % filename att.setAttachmentFile(attf) att.unmarkCreationFlag() renameAfterCreation(att) atts = ar.getAttachment() + [att] if ar.getAttachment() else [att] atts = [a.UID() for a in atts] ar.setAttachment(atts) for ar_or_sample in ars_or_samples: # Attach the pdf to the Analysis Request if ISample.providedBy(ar_or_sample): for ar in ar_or_sample.getAnalysisRequests(): _attach_to_ar(pdf, ar) elif IAnalysisRequest.providedBy(ar_or_sample): _attach_to_ar(pdf, ar_or_sample) return pdf_fn
def get_rejection_pdf(sample): """Generates a pdf with sample rejection reasons """ # Avoid circular dependencies from bika.lims.browser.analysisrequest.reject import \ AnalysisRequestRejectPdfView # Render the html's rejection document tpl = AnalysisRequestRejectPdfView(sample, api.get_request()) html = tpl.template() html = safe_unicode(html).encode("utf-8") # Generate the pdf return createPdf(htmlreport=html)
def printFromHTML(self, sr_html): """ Tis function generates a pdf file from the html :sr_html: the html to use to generate the pdf """ # HTML written to debug file debug_mode = App.config.getConfiguration().debug_mode if debug_mode: tmp_fn = tempfile.mktemp(suffix=".html") open(tmp_fn, "wb").write(sr_html) # Creates the pdf # we must supply the file ourself so that createPdf leaves it alone. pdf_fn = tempfile.mktemp(suffix=".pdf") pdf_report = createPdf(htmlreport=sr_html, outfile=pdf_fn) return pdf_report
def printFromHTML(self, code_html): """ Tis function generates a pdf file from the html :code_html: the html to use to generate the pdf """ # HTML written to debug file debug_mode = App.config.getConfiguration().debug_mode if debug_mode: tmp_fn = tempfile.mktemp(suffix=".html") open(tmp_fn, "wb").write(code_html) # Creates the pdf # we must supply the file ourself so that createPdf leaves it alone. pdf_fn = tempfile.mktemp(suffix=".pdf") pdf_report = createPdf(htmlreport=code_html, outfile=pdf_fn) return pdf_report
def generate_requisition_pdf(ar_or_sample): if not ar_or_sample: logger.warn("No Analysis Request or Sample provided") return if ISample.providedBy(ar_or_sample): for ar in ar_or_sample.getAnalysisRequests(): generate_requisition_pdf(ar) return elif not IAnalysisRequest.providedBy(ar_or_sample): logger.warn("Type not supported: {}".format(repr(ar_or_sample))) return html = RequisitionFormPdf(ar_or_sample, ar_or_sample.REQUEST).template() html = safe_unicode(html).encode('utf-8') filename = '%s-requisition' % ar_or_sample.id pdf_fn = tempfile.mktemp(suffix=".pdf") pdf = createPdf(htmlreport=html, outfile=pdf_fn) if not pdf: logger.warn( "Unable to generate the PDF of requisition form for {}".format( ar_or_sample.id)) return # Attach the pdf to the Analysis Request attid = ar_or_sample.aq_parent.generateUniqueId('Attachment') att = _createObjectByType("Attachment", ar_or_sample.aq_parent, attid) att.setAttachmentFile(open(pdf_fn)) att.setReportOption('i') # Ignore in report # Try to assign the Requisition Attachment Type query = dict(portal_type='AttachmentType', title='Requisition') brains = api.search(query, 'bika_setup_catalog') if brains: att_type = api.get_object(brains[0]) att.setAttachmentType(att_type) # Awkward workaround to rename the file attf = att.getAttachmentFile() attf.filename = '%s.pdf' % filename att.setAttachmentFile(attf) att.unmarkCreationFlag() renameAfterCreation(att) atts = ar_or_sample.getAttachment() + [att] if \ ar_or_sample.getAttachment() else [att] atts = [a.UID() for a in atts] ar_or_sample.setAttachment(atts) os.remove(pdf_fn)
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 __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 __call__(self): pc = self.portal_catalog self.checkPermission = self.context.portal_membership.checkPermission self.now = DateTime() self.SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled() # Client details (if client is associated) self.client = None client_uid = hasattr(self.context, 'getClientUID') and self.context.getClientUID() if client_uid: proxies = pc(portal_type='Client', UID=client_uid) if proxies: self.client = proxies[0].getObject() client_address = self.client.getPostalAddress() if self.contact and not client_address: client_address = self.contact.getBillingAddress() if not client_address: client_address = self.contact.getPhysicalAddress() if client_address: _keys = ['address', 'city', 'state', 'zip', 'country'] _list = [client_address.get(v) for v in _keys if client_address.get(v)] self.client_address = "<br/>".join(_list).replace("\n", "<br/>") if self.client_address.endswith("<br/>"): self.client_address = self.client_address[:-5] else: self.client_address = None # Reporter self.member = self.context.portal_membership.getAuthenticatedMember() self.username = self.member.getUserName() self.reporter = self.user_fullname(self.username) self.reporter_email = self.user_email(self.username) self.reporter_signature = "" c = [x for x in self.bika_setup_catalog(portal_type='LabContact') if x.getObject().getUsername() == self.username] if c: sf = c[0].getObject().getSignature() if sf: self.reporter_signature = sf.absolute_url() + "/Signature" # laboratory self.laboratory = self.context.bika_setup.laboratory self.accredited = self.laboratory.getLaboratoryAccredited() lab_address = self.laboratory.getPrintAddress() if lab_address: _keys = ['address', 'city', 'state', 'zip', 'country'] _list = [lab_address.get(v) for v in _keys if lab_address.get(v)] self.lab_address = "<br/>".join(_list).replace("\n", "<br/>") if self.lab_address.endswith("<br/>"): self.lab_address = self.lab_address[:-5] else: self.lab_address = None # Analysis Request results self.ars = [] self.ar_headers = [_("Request ID"), _("Date Requested"), _("Sample Type"), _("Sample Point")] self.analysis_headers = [_("Analysis Service"), _("Method"), _("Result"), _("Analyst")] for ar in self.context.getAnalysisRequests(): datecreated = ar.created() # datereceived = ar.getDateReceived() # datepublished = ar.getDatePublished() datalines = [] for analysis in ar.getAnalyses(full_objects=True): service = analysis.getService() method = service.getMethod() sample = ar.getSample() result = analysis.getResult() try: precision = service.getPrecision() and service.getPrecision() or "2" result = float(result) formatted_result = str("%." + precision + "f") % result except: precision = "2" formatted_result = result datalines.append({_("Analysis Service"): analysis.getService().Title(), _("Method"): method and method.Title() or "", _("Result"): formatted_result, _("Analyst"): self.user_fullname(analysis.getAnalyst()), _("Remarks"): analysis.getRemarks()}) self.ars.append({ _("Request ID"): ar.getRequestID(), _("Date Requested"): self.ulocalized_time(datecreated), # requested->created _("Sample Type"): sample.getSampleType() and sample.getSampleType().Title() or '', _("Sample Point"): sample.getSamplePoint() and sample.getSamplePoint().Title() or '', _("datalines"): datalines, }) # Create Report fn = self.context.Title() + " " + self.ulocalized_time(self.now) report_html = self.template() debug_mode = App.config.getConfiguration().debug_mode if debug_mode: open(os.path.join(Globals.INSTANCE_HOME, 'var', fn + ".html"), "w").write(report_html) ramdisk = StringIO() pdf = createPdf(report_html, ramdisk) pdf_data = ramdisk.getvalue() ramdisk.close() if debug_mode: open(os.path.join(Globals.INSTANCE_HOME, 'var', fn + ".pdf"), "wb").write(pdf_data) # XXX Email published batches to who? # Send PDF to browser if not pdf.err: setheader = self.request.RESPONSE.setHeader setheader('Content-Type', 'application/pdf') setheader("Content-Disposition", "attachment;filename=\"%s\"" % fn) self.request.RESPONSE.write(pdf_data)
def __call__(self): """Create and render selected report """ # if there's an error, we return productivity.pt which requires these. self.selection_macros = SelectionMacrosView(self.context, self.request) self.additional_reports = [] adapters = getAdapters((self.context, ), IProductivityReport) for name, adapter in adapters: report_dict = adapter(self.context, self.request) report_dict['id'] = name self.additional_reports.append(report_dict) report_id = self.request.get('report_id', '') if not report_id: message = "No report specified in request" self.logger.error(message) self.context.plone_utils.addPortalMessage(message, 'error') return self.template() self.date = DateTime() 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 = self.context.bika_setup.laboratory self.laboratory = lab self.lab_title = lab.getName() self.lab_address = lab.getPrintAddress() self.lab_email = lab.getEmailAddress() self.lab_url = lab.getLabURL() client = logged_in_client(self.context) if client: clientuid = client.UID() self.client_title = client.Title() self.client_address = client.getPrintAddress() else: clientuid = None self.client_title = None self.client_address = None # Render form output # the report can add file names to this list; they will be deleted # once the PDF has been generated. temporary plot image files, etc. self.request['to_remove'] = [] if "report_module" in self.request: module = self.request["report_module"] else: module = "bika.lims.browser.reports.%s" % report_id try: exec("from %s import Report" % module) # required during error redirect: the report must have a copy of # additional_reports, because it is used as a surrogate view. Report.additional_reports = self.additional_reports except ImportError: message = "Report %s.Report not found (shouldn't happen)" % module self.logger.error(message) self.context.plone_utils.addPortalMessage(message, 'error') return self.template() # Report must return dict with: # - report_title - title string for pdf/history listing # - report_data - rendered report output = Report(self.context, self.request)() # if CSV output is chosen, report returns None if not output: return if type(output) in (str, unicode, bytes): # remove temporary files for f in self.request['to_remove']: os.remove(f) return output # The report output gets pulled through report_frame.pt self.reportout = output['report_data'] framed_output = self.frame_template() # this is the good part result = createPdf(framed_output) # remove temporary files for f in self.request['to_remove']: os.remove(f) if result: # Create new report object reportid = self.aq_parent.generateUniqueId('Report') self.aq_parent.invokeFactory(id=reportid, type_name="Report") report = self.aq_parent._getOb(reportid) report.edit(Client=clientuid) report.processForm() # write pdf to report object report.edit(title=output['report_title'], ReportFile=result) report.reindexObject() fn = "%s - %s" % (self.date.strftime(self.date_format_short), _u(output['report_title'])) setheader = self.request.RESPONSE.setHeader setheader('Content-Type', 'application/pdf') setheader("Content-Disposition", "attachment;filename=\"%s\"" % _c(fn)) self.request.RESPONSE.write(result) return
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 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') debug_mode = App.config.getConfiguration().debug_mode if debug_mode: open(join(Globals.INSTANCE_HOME,'var', out_fn + ".html"), "w").write(ar_results) ramdisk = StringIO() pdf = 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 create_pdf(self): """Create the invoice PDF """ invoice = self.template() return createPdf(invoice)
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): html = super(PrintView, self).__call__() pdf = createPdf(html) filename = "{}.pdf".format(self.context.getId()) return self.download(pdf, filename)
def __call__(self): pc = self.portal_catalog self.checkPermission = self.context.portal_membership.checkPermission self.now = DateTime() self.SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled() # Client details (if client is associated) self.client = None client_uid = hasattr(self.context, 'getClientUID') and self.context.getClientUID() if client_uid: proxies = pc(portal_type='Client', UID=client_uid) if proxies: self.client = proxies[0].getObject() client_address = self.client.getPostalAddress() if self.contact and not client_address: client_address = self.contact.getBillingAddress() if not client_address: client_address = self.contact.getPhysicalAddress() if client_address: _keys = ['address', 'city', 'state', 'zip', 'country'] _list = [client_address.get(v) for v in _keys if client_address.get(v)] self.client_address = "<br/>".join(_list).replace("\n", "<br/>") if self.client_address.endswith("<br/>"): self.client_address = self.client_address[:-5] else: self.client_address = None # Reporter self.member = self.context.portal_membership.getAuthenticatedMember() self.username = self.member.getUserName() self.reporter = self.user_fullname(self.username) self.reporter_email = self.user_email(self.username) self.reporter_signature = "" c = [x for x in self.bika_setup_catalog(portal_type='LabContact') if x.getObject().getUsername() == self.username] if c: sf = c[0].getObject().getSignature() if sf: self.reporter_signature = sf.absolute_url() + "/Signature" # laboratory self.laboratory = self.context.bika_setup.laboratory self.accredited = self.laboratory.getLaboratoryAccredited() lab_address = self.laboratory.getPrintAddress() if lab_address: _keys = ['address', 'city', 'state', 'zip', 'country'] _list = [lab_address.get(v) for v in _keys if lab_address.get(v)] self.lab_address = "<br/>".join(_list).replace("\n", "<br/>") if self.lab_address.endswith("<br/>"): self.lab_address = self.lab_address[:-5] else: self.lab_address = None # Analysis Request results self.ars = [] self.ar_headers = [_("Request ID"), _("Date Requested"), _("Sample Type"), _("Sample Point")] self.analysis_headers = [_("Analysis Service"), _("Method"), _("Result"), _("Analyst")] for ar in self.context.getAnalysisRequests(): datecreated = ar.created() datalines = [] for analysis in ar.getAnalyses(full_objects=True): method = analysis.getMethod() sample = ar.getSample() result = analysis.getResult() formatted_result = format_numeric_result(analysis, result) datalines.append({_("Analysis Service"): analysis.Title(), _("Method"): method and method.Title() or "", _("Result"): formatted_result, _("Analyst"): self.user_fullname(analysis.getAnalyst()), _("Remarks"): analysis.getRemarks()}) self.ars.append({ _("Request ID"): ar.getId(), _("Date Requested"): self.ulocalized_time(datecreated), # requested->created _("Sample Type"): sample.getSampleType() and sample.getSampleType().Title() or '', _("Sample Point"): sample.getSamplePoint() and sample.getSamplePoint().Title() or '', _("datalines"): datalines, }) # Create Report fn = self.context.Title() + " " + self.ulocalized_time(self.now) report_html = self.template() debug_mode = App.config.getConfiguration().debug_mode if debug_mode: tmp_fd, tmp_fn = tempfile.mkstemp(suffix=".html") logger.debug("Writing HTML for %s to %s" % (self.context, tmp_fn)) tmp_fd.write(report_html) tmp_fd.close() pdf_fd, pdf_fn = tempfile.mkstemp(suffix="pdf") pdf_fd.close() pdf = createPdf(report_html, outfile=pdf_fn) if debug_mode: logger.debug("Wrote PDF for %s to %s" % (self.context, pdf_fn)) else: os.remove(pdf_fn) # XXX Email published batches to who? # Send PDF to browser if not pdf.err: setheader = self.request.RESPONSE.setHeader setheader('Content-Type', 'application/pdf') setheader("Content-Disposition", "attachment;filename=\"%s\"" % fn) self.request.RESPONSE.write(pdf)
def toPdf(self): html = safe_unicode(self.template()).encode('utf-8') pdf_data = createPdf(html) return pdf_data
def __call__(self): pc = self.portal_catalog bc = self.bika_catalog bsc = self.bika_setup_catalog self.checkPermission = self.context.portal_membership.checkPermission self.now = DateTime() self.SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled() # Client details (if client is associated) self.client = None client_uid = hasattr(self.context, "getClientUID") and self.context.getClientUID() if client_uid: proxies = pc(portal_type="Client", UID=client_uid) if proxies: self.client = proxies[0].getObject() 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 if client_address.get(v)] self.client_address = "<br/>".join(_list).replace("\n", "<br/>") if self.client_address.endswith("<br/>"): self.client_address = self.client_address[:-5] else: self.client_address = None # Reporter self.member = self.context.portal_membership.getAuthenticatedMember() self.username = self.member.getUserName() self.reporter = self.user_fullname(self.username) self.reporter_email = self.user_email(self.username) self.reporter_signature = "" c = [ x for x in self.bika_setup_catalog(portal_type="LabContact") if x.getObject().getUsername() == self.username ] if c: sf = c[0].getObject().getSignature() if sf: self.reporter_signature = sf.absolute_url() + "/Signature" # laboratory self.laboratory = self.context.bika_setup.laboratory self.accredited = self.laboratory.getLaboratoryAccredited() lab_address = self.laboratory.getPrintAddress() if lab_address: _keys = ["address", "city", "state", "zip", "country"] _list = [lab_address.get(v) for v in _keys if lab_address.get(v)] self.lab_address = "<br/>".join(_list).replace("\n", "<br/>") if self.lab_address.endswith("<br/>"): self.lab_address = self.lab_address[:-5] else: self.lab_address = None # Analysis Request results self.ars = [] self.ar_headers = [_("Request ID"), _("Date Requested"), _("Sample Type"), _("Sample Point")] self.analysis_headers = [_("Analysis Service"), _("Method"), _("Result"), _("Analyst")] for ar in self.context.getAnalysisRequests(): datecreated = ar.created() datereceived = ar.getDateReceived() datepublished = ar.getDatePublished() datalines = [] for analysis in ar.getAnalyses(full_objects=True): service = analysis.getService() method = service.getMethod() sample = ar.getSample() result = analysis.getResult() try: precision = service.getPrecision() and service.getPrecision() or "2" result = float(result) formatted_result = str("%." + precision + "f") % result except: precision = "2" formatted_result = result datalines.append( { _("Analysis Service"): analysis.getService().Title(), _("Method"): method and method.Title() or "", _("Result"): formatted_result, _("Analyst"): self.user_fullname(analysis.getAnalyst()), _("Remarks"): analysis.getRemarks(), } ) self.ars.append( { _("Request ID"): ar.getRequestID(), _("Date Requested"): self.ulocalized_time(datecreated), # requested->created _("Sample Type"): sample.getSampleType() and sample.getSampleType().Title() or "", _("Sample Point"): sample.getSamplePoint() and sample.getSamplePoint().Title() or "", _("datalines"): datalines, } ) # Create Report fn = self.context.Title() + " " + self.ulocalized_time(self.now) report_html = self.template() debug_mode = App.config.getConfiguration().debug_mode if debug_mode: open(os.path.join(Globals.INSTANCE_HOME, "var", fn + ".html"), "w").write(report_html) ramdisk = StringIO() pdf = createPdf(report_html, ramdisk) pdf_data = ramdisk.getvalue() ramdisk.close() if debug_mode: open(os.path.join(Globals.INSTANCE_HOME, "var", fn + ".pdf"), "wb").write(pdf_data) # Email to who? # Send PDF to browser if not pdf.err: setheader = self.request.RESPONSE.setHeader setheader("Content-Type", "application/pdf") setheader("Content-Disposition", 'attachment;filename="%s"' % fn) self.request.RESPONSE.write(pdf_data)
def toPdf(self): outpath = join(Globals.INSTANCE_HOME, 'var') filepath = join(outpath, tmpID() + ".pdf") html = safe_unicode(self.template()).encode('utf-8') return createPdf(html, filepath)
def generate_delivery_pdf(context, ars_or_samples): if not ars_or_samples: logger.warn("No Analysis Requests or Samples provided") return if ISample.providedBy(ars_or_samples) or \ IAnalysisRequest.providedBy(ars_or_samples): return generate_delivery_pdf(context, [ars_or_samples]) if not isinstance(ars_or_samples, list): logger.warn("Type not supported: {}".format(repr(ars_or_samples))) return html = DeliveryFormPdf(context, context.REQUEST, analysis_requests=ars_or_samples).template() html = safe_unicode(html).encode("utf-8") filename = "delivery" pdf_fn = tempfile.mktemp(suffix=".pdf") pdf = createPdf(htmlreport=html, outfile=pdf_fn) if not pdf: ar_ids = map(lambda ar: ar.id, ars_or_samples) logger.warn("Unable to generate the PDF of delivery form for {}". format(' '.join(ar_ids))) return None def _attach_to_ar(pdf, ar_brain_or_obj): ar = api.get_object(ar_brain_or_obj) # Attach the pdf to the Analysis Request attid = ar.aq_parent.generateUniqueId('Attachment') att = _createObjectByType( "Attachment", ar.aq_parent, attid) att.setAttachmentFile(open(pdf_fn)) att.setReportOption('i') # Ignore in report # Try to assign the Requisition Attachment Type query = dict(portal_type='AttachmentType', title='Delivery') brains = api.search(query, 'bika_setup_catalog') if brains: att_type = api.get_object(brains[0]) att.setAttachmentType(att_type) # Awkward workaround to rename the file attf = att.getAttachmentFile() attf.filename = '%s.pdf' % filename att.setAttachmentFile(attf) att.unmarkCreationFlag() renameAfterCreation(att) atts = ar.getAttachment() + [att] if ar.getAttachment() else [att] atts = [a.UID() for a in atts] ar.setAttachment(atts) # TODO Create only one Attachment per Client and assign it to all ARs # There is no need to creat a single Attachment object for each AR. Same # attachment can be assigned to different ARs and they will resolve the # attachment correctly later. This will be useful for: # a) Reduce the database size (less pdfs to store) # b) workflow_download_delivery can easily return the attachments that are # different when multiple ARs are selected. for ar_or_sample in ars_or_samples: # Attach the pdf to the Analysis Request if ISample.providedBy(ar_or_sample): for ar in ar_or_sample.getAnalysisRequests(): _attach_to_ar(pdf, ar) elif IAnalysisRequest.providedBy(ar_or_sample): _attach_to_ar(pdf, ar_or_sample) return pdf_fn
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') debug_mode = App.config.getConfiguration().debug_mode if debug_mode: open( join(Globals.INSTANCE_HOME, 'var', out_fn + ".html"), "w").write(ar_results) ramdisk = StringIO() pdf = 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 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 __call__(self): """Create and render selected report """ # if there's an error, we return productivity.pt which requires these. self.selection_macros = SelectionMacrosView(self.context, self.request) self.additional_reports = [] adapters = getAdapters((self.context, ), IProductivityReport) for name, adapter in adapters: report_dict = adapter(self.context, self.request) report_dict['id'] = name self.additional_reports.append(report_dict) report_id = self.request.get('report_id', '') if not report_id: message = _("No report specified in request") self.logger.error(message) self.context.plone_utils.addPortalMessage(message, 'error') return self.template() self.date = DateTime() 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 = self.context.bika_setup.laboratory self.laboratory = lab self.lab_title = lab.getName() self.lab_address = lab.getPrintAddress() self.lab_email = lab.getEmailAddress() self.lab_url = lab.getLabURL() client = logged_in_client(self.context) if client: clientuid = client.UID() self.client_title = client.Title() self.client_address = client.getPrintAddress() else: clientuid = None self.client_title = None self.client_address = None # Render form output # the report can add file names to this list; they will be deleted # once the PDF has been generated. temporary plot image files, etc. self.request['to_remove'] = [] if "report_module" in self.request: module = self.request["report_module"] else: module = "bika.lims.browser.reports.%s" % report_id try: exec("from %s import Report" % module) # required during error redirect: the report must have a copy of # additional_reports, because it is used as a surrogate view. Report.additional_reports = self.additional_reports except ImportError: message = "Report %s.Report not found (shouldn't happen)" % module self.logger.error(message) self.context.plone_utils.addPortalMessage(message, 'error') return self.template() # Report must return dict with: # - report_title - title string for pdf/history listing # - report_data - rendered report output = Report(self.context, self.request)() # if CSV output is chosen, report returns None if not output: return if type(output) in (str, unicode, bytes): # remove temporary files for f in self.request['to_remove']: os.remove(f) return output # The report output gets pulled through report_frame.pt self.reportout = output['report_data'] framed_output = self.frame_template() # this is the good part result = createPdf(framed_output) # remove temporary files for f in self.request['to_remove']: os.remove(f) if result: # Create new report object reportid = self.aq_parent.generateUniqueId('Report') report = _createObjectByType("Report", self.aq_parent, reportid) report.edit(Client=clientuid) report.processForm() # write pdf to report object report.edit(title=output['report_title'], ReportFile=result) report.reindexObject() fn = "%s - %s" % (self.date.strftime( self.date_format_short), _u(output['report_title'])) setheader = self.request.RESPONSE.setHeader setheader('Content-Type', 'application/pdf') setheader("Content-Disposition", "attachment;filename=\"%s\"" % _c(fn)) self.request.RESPONSE.write(result) return
def __call__(self): pc = self.portal_catalog self.checkPermission = self.context.portal_membership.checkPermission self.now = DateTime() self.SamplingWorkflowEnabled = self.context.bika_setup.getSamplingWorkflowEnabled() # Client details (if client is associated) self.client = None client_uid = hasattr(self.context, 'getClientUID') and self.context.getClientUID() if client_uid: proxies = pc(portal_type='Client', UID=client_uid) if proxies: self.client = proxies[0].getObject() client_address = self.client.getPostalAddress() if self.contact and not client_address: client_address = self.contact.getBillingAddress() if not client_address: client_address = self.contact.getPhysicalAddress() if client_address: _keys = ['address', 'city', 'state', 'zip', 'country'] _list = [client_address.get(v) for v in _keys if client_address.get(v)] self.client_address = "<br/>".join(_list).replace("\n", "<br/>") if self.client_address.endswith("<br/>"): self.client_address = self.client_address[:-5] else: self.client_address = None # Reporter self.member = self.context.portal_membership.getAuthenticatedMember() self.username = self.member.getUserName() self.reporter = self.user_fullname(self.username) self.reporter_email = self.user_email(self.username) self.reporter_signature = "" c = [x for x in self.bika_setup_catalog(portal_type='LabContact') if x.getObject().getUsername() == self.username] if c: sf = c[0].getObject().getSignature() if sf: self.reporter_signature = sf.absolute_url() + "/Signature" # laboratory self.laboratory = self.context.bika_setup.laboratory self.accredited = self.laboratory.getLaboratoryAccredited() lab_address = self.laboratory.getPrintAddress() if lab_address: _keys = ['address', 'city', 'state', 'zip', 'country'] _list = [lab_address.get(v) for v in _keys if lab_address.get(v)] self.lab_address = "<br/>".join(_list).replace("\n", "<br/>") if self.lab_address.endswith("<br/>"): self.lab_address = self.lab_address[:-5] else: self.lab_address = None # Analysis Request results self.ars = [] self.ar_headers = [_("Request ID"), _("Date Requested"), _("Sample Type"), _("Sample Point")] self.analysis_headers = [_("Analysis Service"), _("Method"), _("Result"), _("Analyst")] for ar in self.context.getAnalysisRequests(): datecreated = ar.created() # datereceived = ar.getDateReceived() # datepublished = ar.getDatePublished() datalines = [] for analysis in ar.getAnalyses(full_objects=True): service = analysis.getService() method = service.getMethod() sample = ar.getSample() result = analysis.getResult() formatted_result = format_numeric_result(analysis, result) datalines.append({_("Analysis Service"): analysis.getService().Title(), _("Method"): method and method.Title() or "", _("Result"): formatted_result, _("Analyst"): self.user_fullname(analysis.getAnalyst()), _("Remarks"): analysis.getRemarks()}) self.ars.append({ _("Request ID"): ar.getRequestID(), _("Date Requested"): self.ulocalized_time(datecreated), # requested->created _("Sample Type"): sample.getSampleType() and sample.getSampleType().Title() or '', _("Sample Point"): sample.getSamplePoint() and sample.getSamplePoint().Title() or '', _("datalines"): datalines, }) # Create Report fn = self.context.Title() + " " + self.ulocalized_time(self.now) report_html = self.template() debug_mode = App.config.getConfiguration().debug_mode if debug_mode: tmp_fd, tmp_fn = tempfile.mkstemp(suffix=".html") logger.debug("Writing HTML for %s to %s" % (self.context, tmp_fn)) tmp_fd.write(report_html) tmp_fd.close() pdf_fd, pdf_fn = tempfile.mkstemp(suffix="pdf") pdf_fd.close() pdf = createPdf(report_html, outfile=pdf_fn) if debug_mode: logger.debug("Wrote PDF for %s to %s" % (self.context, pdf_fn)) else: os.remove(pdf_fn) # XXX Email published batches to who? # Send PDF to browser if not pdf.err: setheader = self.request.RESPONSE.setHeader setheader('Content-Type', 'application/pdf') setheader("Content-Disposition", "attachment;filename=\"%s\"" % fn) self.request.RESPONSE.write(pdf)