class JSONReadExtender(object): """- Adds the full details of all analyses to the AR.Analyses field """ implements(IJSONReadExtender) adapts(IAnalysisRequest) def __init__(self, context): self.context = context def ar_analysis_values(self): ret = [] analyses = self.context.getAnalyses(cancellation_state='active') for proxy in analyses: analysis = proxy.getObject() service = analysis.getService() if proxy.review_state == 'retracted': # these are scraped up when Retested analyses are found below. continue # things that are manually inserted into the analysis. # These things will be included even if they are not present in # include_fields in the request. method = analysis.getMethod() if not method: method = service.getMethod() service = analysis.getService() analysis_data = { "Uncertainty": service.getUncertainty(analysis.getResult()), "Method": method.Title() if method else '', "Unit": service.getUnit(), } # Place all schema fields ino the result. analysis_data.update(load_brain_metadata(proxy, [])) # Place all schema fields ino the result. analysis_data.update(load_field_values(analysis, [])) # call any adapters that care to modify the Analysis data. # adapters = getAdapters((analysis, ), IJSONReadExtender) # for name, adapter in adapters: # adapter(request, analysis_data) if not self.include_fields or "transitions" in self.include_fields: analysis_data['transitions'] = get_workflow_actions(analysis) if analysis.getRetested(): retracted = self.context.getAnalyses(review_state='retracted', title=analysis.Title(), full_objects=True) prevs = sorted(retracted, key=lambda item: item.created()) prevs = [{ 'created': str(p.created()), 'Result': p.getResult(), 'InterimFields': p.getInterimFields() } for p in prevs] analysis_data['Previous Results'] = prevs ret.append(analysis_data) return ret def __call__(self, request, data): self.request = request self.include_fields = get_include_fields(request) if not self.include_fields or "Analyses" in self.include_fields: data['Analyses'] = self.ar_analysis_values()
class ResultOutOfRange(object): """Return alerts for any analyses inside the context ar """ implements(IFieldIcons) adapts(IAnalysisRequest) def __init__(self, context): self.context = context def __call__(self, result=None, **kwargs): workflow = getToolByName(self.context, 'portal_workflow') items = self.context.getAnalyses() field_icons = {} for obj in items: obj = obj.getObject() if hasattr(obj, 'getObject') else obj uid = obj.UID() astate = workflow.getInfoFor(obj, 'review_state') if astate == 'retracted': continue adapters = getAdapters((obj, ), IFieldIcons) for name, adapter in adapters: alerts = adapter(obj) if alerts: if uid in field_icons: field_icons[uid].extend(alerts[uid]) else: field_icons[uid] = alerts[uid] return field_icons
class JSONReadExtender(object): """Adds the UID to the ResultsRange dict. This will go away when we stop using keywords for this stuff. """ implements(IJSONReadExtender) adapts(IAnalysisSpec) def __init__(self, context): self.context = context def __call__(self, request, data): bsc = self.context.bika_setup_catalog rr = [] for i, x in enumerate(data.get("ResultsRange", [])): keyword = x.get("keyword") proxies = bsc(portal_type="AnalysisService", getKeyword=keyword) if proxies: data['ResultsRange'][i]['uid'] = proxies[0].UID
class CalculationResultAlerts(object): """This uses IAnalysis.ResultOutOfRange on values in request. To validate results at ajax calculation time, make more adapters like this one, from IFieldIcons. Any existing IAnalysis/IFieldIcon adapters (AnalysisOutOfRange) have already been called. """ adapts(IAnalysis) implements(IFieldIcons) def __init__(self, context): self.context = context def __call__(self, result=None, specification=None, **kwargs): workflow = getToolByName(self.context, 'portal_workflow') astate = workflow.getInfoFor(self.context, 'review_state') if astate == 'retracted': return {} result = self.context.getResult() if result is None else result alerts = {} path = '++resource++bika.lims.images' uid = self.context.UID() try: indet = result.startswith("<") or result.startswith(">") except AttributeError: indet = False if indet: alert = { 'field': 'Result', 'icon': path + '/exclamation.png', 'msg': t(_("Indeterminate result")) } if uid in alerts: alerts[uid].append(alert) else: alerts[uid] = [ alert, ] return alerts
class JSONReadExtender(object): """- Adds the specification from Analysis Request to Analysis in JSON response """ implements(IJSONReadExtender) adapts(IAnalysis) def __init__(self, context): self.context = context def analysis_specification(self): ar = self.context.aq_parent rr = dicts_to_dict(ar.getResultsRange(), 'keyword') return rr[self.context.getService().getKeyword()] def __call__(self, request, data): self.request = request self.include_fields = get_include_fields(request) if not self.include_fields or "specification" in self.include_fields: data['specification'] = self.analysis_specification() return data
class JSONReadExtender(object): """- Place additional information about profile services into the returned records. Used in AR Add to prevent extra requests """ implements(IJSONReadExtender) adapts(IAnalysisProfile) def __init__(self, context): self.context = context def __call__(self, request, data): service_data = [] for service in self.context.getService(): this_service = {'UID': service.UID(), 'Title': service.Title(), 'Keyword': service.getKeyword(), 'Price': service.getPrice(), 'VAT': service.getVAT(), 'PointOfCapture': service.getPointOfCapture(), 'CategoryTitle': service.getCategory().Title()} service_data.append(this_service) data['service_data'] = service_data
class JSONReadExtender(object): """- Place additional information about profile services into the returned records. Used in AR Add to prevent extra requests """ implements(IJSONReadExtender) adapts(IARTemplate) def __init__(self, context): self.context = context def render_template_partitions(self): """ Supplies a more detailed view of the Partitions for this template. It's built to mimic the partitions that are stored in the ar_add form state variable, so that when a partition is chosen, there is no further translation necessary. It combines the Analyses and Partitions AT schema field values. For some fields (separate, minvol) there is no information, when partitions are specified in the AR Template. :return a list of dictionaries like this: container [] container_titles [] preservation [] preservation_titles [] separate false minvol "0.0000 m3 " services ["2fdc040e05bb42ca8b52e41761fdb795", 6 more...] service_titles ["Copper", "Iron", "Magnesium", 4 more...] """ Analyses = self.context.Schema()['Analyses'].get(self.context) Parts = self.context.Schema()['Partitions'].get(self.context) if not Parts: # default value copied in from content/artemplate.py Parts = [{'part_id': 'part-1', 'Container': '', 'Preservation': '', 'container_uid': '', 'preservation_uid': ''}] parts = [] not_found = set() for Part in Parts: part = { 'part_id': Part.get("part_id", "part-1"), 'container_titles': Part.get("Container", ""), 'container': Part.get("container_uid", ""), 'preservation_titles': Part.get("Preservation", ""), 'preservation': Part.get("preservation_uid", ""), 'services': [], 'service_titles': [], } for analysis in Analyses: uid = analysis['service_uid'] partiton = analysis['partition'] if partiton == part['part_id']: part['services'].append(uid) part['service_titles'].append(uid) not_found.discard(analysis['service_uid']) else: if uid in part['services']: part['services'].remove(uid) if uid in part['service_titles']: part['service_titles'].remove(uid) not_found.add(analysis['service_uid']) parts.append(part) # all others go into the first part. Mostly this will be due to # partition info not being defined? for uid in not_found: if uid not in part['services']: parts[0]['services'].append(uid) if uid not in part['service_titles']: parts[0]['service_titles'].append(uid) return parts def __call__(self, request, data): bsc = self.context.bika_setup_catalog service_data = [] for item in self.context.getAnalyses(): service_uid = item['service_uid'] service = bsc(UID=service_uid)[0].getObject() this_service = {'UID': service.UID(), 'Title': service.Title(), 'Keyword': service.getKeyword(), 'Price': service.getPrice(), 'VAT': service.getVAT(), 'PointOfCapture': service.getPointOfCapture(), 'CategoryTitle': service.getCategory().Title()} service_data.append(this_service) data['service_data'] = service_data data['Partitions'] = self.render_template_partitions()
class JSONReadExtender(object): """- Adds fields to Analysis Service: ServiceDependencies - services our calculation depends on ServiceDependants - services who's calculation depend on us MethodInstruments - A dictionary of instruments: keys: Method UID values: list of instrument UIDs """ implements(IJSONReadExtender) adapts(IAnalysisService) def __init__(self, context): self.context = context def service_info(self, service): ret = { "Category": service.getCategory().Title(), "Category_uid": service.getCategory().UID(), "Service": service.Title(), "Service_uid": service.UID(), "Keyword": service.getKeyword(), "PointOfCapture": service.getPointOfCapture(), "PointOfCapture_title": POINTS_OF_CAPTURE.getValue(service.getPointOfCapture()), } return ret def __call__(self, request, data): include_fields = get_include_fields(request) if not include_fields or "ServiceDependencies" in include_fields: data["ServiceDependencies"] = [] calc = self.context.getCalculation() if calc: services = [ self.service_info(service) for service in calc.getCalculationDependencies(flat=True) if service.UID() != self.context.UID() ] data["ServiceDependencies"] = services if not include_fields or "ServiceDependants" in include_fields: data["ServiceDependants"] = [] calcs = self.context.getBackReferences( 'CalculationAnalysisService') if calcs: for calc in calcs: services = [ self.service_info(service) for service in calc.getCalculationDependants() if service.UID() != self.context.UID() ] data["ServiceDependants"].extend(services) if not include_fields or "MethodInstruments" in include_fields: data["MethodInstruments"] = {} for method in self.context.getAvailableMethods(): for instrument in method.getInstruments(): if method.UID() not in data["MethodInstruments"]: data["MethodInstruments"][method.UID()] = [] data["MethodInstruments"][method.UID()].append( load_field_values(instrument, include_fields=[]))