diff --git a/src/senaite/referral/adapters/guards/sample.py b/src/senaite/referral/adapters/guards/sample.py index d225589..38a8a95 100644 --- a/src/senaite/referral/adapters/guards/sample.py +++ b/src/senaite/referral/adapters/guards/sample.py @@ -67,3 +67,14 @@ def guard_invalidate_at_reference(self): if not lab_code: return False return True + + def guard_receive_at_reference(self): + """Returns true if current request contains a POST with the + 'receive_at_reference' action to ensure this transition is not + performed manually, + """ + request = api.get_request() + lab_code = request.get("lab_code") + if not lab_code: + return False + return True diff --git a/src/senaite/referral/adapters/listing/samples.py b/src/senaite/referral/adapters/listing/samples.py index 64d59f5..e21b448 100644 --- a/src/senaite/referral/adapters/listing/samples.py +++ b/src/senaite/referral/adapters/listing/samples.py @@ -103,7 +103,11 @@ def add_review_states(self): "id": "shipped", "title": _("Referred"), "contentFilter": { - "review_state": ("shipped", "rejected_at_reference"), + "review_state": ( + "shipped", + "rejected_at_reference", + "received_at_reference", + ), "sort_on": "created", "sort_order": "descending"}, "transitions": [], diff --git a/src/senaite/referral/content/inboundsample.py b/src/senaite/referral/content/inboundsample.py index 547f430..b9743aa 100644 --- a/src/senaite/referral/content/inboundsample.py +++ b/src/senaite/referral/content/inboundsample.py @@ -125,6 +125,12 @@ class IInboundSampleSchema(model.Schema): ) ) + # TODO 2.x Replace schema.List by senaite.core.schema.UIDReferenceField + directives.omitted("services") + services = schema.List( + title=_(u"label_inboundsample_services", default=u"Services"), + ) + # TODO 2.x Replace schema.List by senaite.core.schema.UIDReferenceField directives.omitted("sample") sample = schema.List( @@ -311,3 +317,21 @@ def getDateRejected(self): """Returns the datetime when this inbound sample was rejected or None """ return get_action_date(self, "reject_inbound_sample", default=None) + + def setServices(self, value): + """Set the services from the current instance that match with the + analyses that were requested by the referring laboratory + """ + set_uids_field_value(self, "services", value) + + def getServices(self): + """Returns the services from current instance that match with the + analyses that were requested by the referring laboratory + """ + return [api.get_object(uid) for uid in self.getRawServices()] + + def getRawServices(self): + """Returns the UIDs of the services from current instance that match + with the analyses that were requested by the referring laboratory + """ + return get_uids_field_value(self, "services") or [] diff --git a/src/senaite/referral/jsonapi/outboundsample.py b/src/senaite/referral/jsonapi/outboundsample.py index 60a269d..debd866 100644 --- a/src/senaite/referral/jsonapi/outboundsample.py +++ b/src/senaite/referral/jsonapi/outboundsample.py @@ -33,6 +33,7 @@ from bika.lims.interfaces import ISubmitted from bika.lims.utils import changeWorkflowState from bika.lims.workflow import doActionFor +from senaite.referral import logger @implementer(IPushConsumer) @@ -65,8 +66,16 @@ def process(self): msg = "No retest found for '%s'" % sample_id raise APIError(500, "ValueError: {}".format(msg)) - # Do not allow to modify the sample if not referred - if api.get_review_status(sample) != "shipped": + # Do not allow to modify the sample if not received at reference + status = api.get_review_status(sample) + if status == "shipped": + # TODO Do not allow the modification of 'shipped' samples + logger.warn("Please upgrade reference instance to latest!!!. The " + "update of samples in 'shipped' statues won't be " + "supported in the near future, but only those in " + "'received_at_reference' status") + + elif status != "received_at_reference": # We don't rise an exception here because maybe the sample was # updated earlier, but the reference lab got a timeout error and # the remote user is now retrying the notification diff --git a/src/senaite/referral/profiles/default/metadata.xml b/src/senaite/referral/profiles/default/metadata.xml index bd38f0d..de9472e 100644 --- a/src/senaite/referral/profiles/default/metadata.xml +++ b/src/senaite/referral/profiles/default/metadata.xml @@ -6,11 +6,10 @@ dependencies before installing this add-on own profile. --> - 2003 + 2005 profile-senaite.lims:default - diff --git a/src/senaite/referral/remotelab.py b/src/senaite/referral/remotelab.py index 950334f..59624b8 100644 --- a/src/senaite/referral/remotelab.py +++ b/src/senaite/referral/remotelab.py @@ -21,7 +21,6 @@ import math from bika.lims import api from bika.lims.interfaces import IAnalysisRequest -from bika.lims.interfaces import IInternalUse from bika.lims.utils import format_supsub from bika.lims.utils.analysis import format_uncertainty from remotesession import RemoteSession @@ -191,27 +190,24 @@ def update_analyses(self, sample, timeout=5): """ def get_valid_analyses(sample): - # Sort by id descending to prioritize newest results if retests + # Get the analyses from current sample that were requested by the + # referring laboratory, sorted by id descending to prioritize + # newest results if retests + inbound_sample = sample.getInboundSample() + services = inbound_sample.getRawServices() kwargs = { "full_objects": True, + "getServiceUID": services, "sort_on": "id", "sort_order": "ascending", } - # Exclude old, but valid analyses with same keyword (e.g retests), + # exclude old, but valid analyses with same keyword (e.g retests), # cause we want to update the referring lab with the newest result analyses = {} valid = ["verified", "published"] for analysis in sample.getAnalyses(**kwargs): - # Skip analyses for internal use - if IInternalUse.providedBy(analysis): - continue - - # Skip hidden, only interested in final results - if analysis.getHidden(): - continue - # Skip analyses not in a suitable status if api.get_review_status(analysis) not in valid: continue diff --git a/src/senaite/referral/setuphandlers.py b/src/senaite/referral/setuphandlers.py index f1ab73d..dae8b10 100644 --- a/src/senaite/referral/setuphandlers.py +++ b/src/senaite/referral/setuphandlers.py @@ -75,12 +75,24 @@ "transitions": ( "verify", "invalidate_at_reference", + "receive_at_reference", "reject_at_reference", "recall_from_shipment" ), # Sample is read-only "permissions_copy_from": "invalid", }, + "received_at_reference": { + "title": "Received at reference lab", + "description": "Sample received at reference laboratory", + "transitions": ( + "verify", + "reject_at_reference", + "invalidate_at_reference", + ), + # Sample is read-only + "permissions_copy_from": "invalid", + }, "rejected_at_reference": { "title": "Rejected at reference lab", "description": "Sample rejected at reference laboratory", @@ -106,6 +118,16 @@ "guard_expr": "python:here.guard_handler('ship')", } }, + "receive_at_reference": { + "title": "Receive sample (at reference lab)", + "new_state": "received_at_reference", + "action": "Received at reference lab", + "guard": { + "guard_permissions": "", + "guard_roles": "", + "guard_expr": "python:here.guard_handler('receive_at_reference')", + } + }, "reject_at_reference": { "title": "Reject sample (at reference lab)", "new_state": "rejected_at_reference", diff --git a/src/senaite/referral/upgrade/v01_00_000.zcml b/src/senaite/referral/upgrade/v01_00_000.zcml index 454804c..b2dc79f 100644 --- a/src/senaite/referral/upgrade/v01_00_000.zcml +++ b/src/senaite/referral/upgrade/v01_00_000.zcml @@ -1,7 +1,6 @@ + xmlns:genericsetup="http://namespaces.zope.org/genericsetup"> + + + +