def create_object(container, portal_type, **data): """Creates an object slug :returns: The new created content object :rtype: object """ if "id" in data: # always omit the id as senaite LIMS generates a proper one id = data.pop("id") logger.warn("Passed in ID '{}' omitted! Senaite LIMS " "generates a proper ID for you".format(id)) try: # Special case for ARs # => return immediately w/o update if portal_type == "AnalysisRequest": obj = create_analysisrequest(container, **data) # Omit values which are already set through the helper data = u.omit(data, "SampleType", "Analyses") # Set the container as the client, as the AR lives in it data["Client"] = container # Standard content creation else: # we want just a minimun viable object and set the data later obj = api.create(container, portal_type) # obj = api.create(container, portal_type, **data) except Unauthorized: fail(401, "You are not allowed to create this content") # Update the object with the given data, but omit the id try: update_object_with_data(obj, data) except APIError: # Failure in creation process, delete the invalid object container.manage_delObjects(obj.id) # reraise the error raise return obj
def ajax_save_reports(self): """Render all reports as PDFs and store them as AR Reports """ # Data sent via async ajax call as JSON data from the frontend data = self.get_json() # This is the html after it was rendered by the client browser and # eventually extended by JavaScript, e.g. Barcodes or Graphs added etc. # N.B. It might also contain multiple reports! html = data.get("html") # Metadata paperformat = data.get("format") template = data.get("template") orientation = data.get("orientation", "portrait") timestamp = DateTime().ISO8601() is_multi_template = self.is_multi_template(template) store_individually = self.store_multireports_individually() # Generate the print CSS with the set format/orientation css = self.get_print_css(paperformat=paperformat, orientation=orientation) logger.info(u"Print CSS: {}".format(css)) # get an publisher instance publisher = self.publisher # add the generated CSS to the publisher publisher.add_inline_css(css) # TODO: Refactor code below to be not AR specific # remember the values of the last iteration for the exit url client_url = None report_uids = None for report_node in publisher.parse_reports(html): # generate the PDF pdf = publisher.write_pdf(report_node) # get contained AR UIDs in this report uids = filter(None, report_node.get("uids", "").split(",")) # get the AR objects objs = map(api.get_object_by_uid, uids) # sort the objects by created to have the most recent object first # -> supersedes https://github.com/senaite/senaite.impress/pull/48 objs = sorted(objs, key=methodcaller("created"), reverse=True) # remember generated report objects reports = [] for obj in objs: # TODO: refactor to adapter # Create a report object which holds the generated PDF title = "Report-{}".format(obj.getId()) report = api.create(obj, "ARReport", title=title) report.edit(AnalysisRequest=api.get_uid(obj), Pdf=pdf, Html=publisher.to_html(report_node), ContainedAnalysisRequests=uids, Metadata={ "template": template, "paperformat": paperformat, "orientation": orientation, "timestamp": timestamp, "contained_requests": uids, }) reports.append(report) client_url = api.get_url(obj.getClient()) # generate report only for the primary object if is_multi_template and not store_individually: break # remember the generated report UIDs for this iteration report_uids = map(api.get_uid, reports) # This is the clicked button name from the ReactJS component action = data.get("action", "save") exit_url = self.context.absolute_url() if all([client_url, report_uids]): endpoint = "reports_listing" if action == "email": endpoint = "email?uids={}".format(",".join(report_uids)) exit_url = "{}/{}".format(client_url, endpoint) return exit_url