Skip to content

Commit

Permalink
Merge branch '1.x' of github.com:senaite/senaite.referral into 2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
xispa committed Jul 22, 2024
2 parents 97990b2 + 75b34ee commit 9785b5d
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 19 deletions.
34 changes: 34 additions & 0 deletions src/senaite/referral/browser/controlpanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,40 @@ class IReferralControlPanel(Interface):
required=0,
)

notify_all_analyses = schema.Bool(
title=_(
u"label_referral_notify_all_analyses",
u"Notify all analyses to referring laboratory"
),
description=_(
u"description_referral_notify_all_analyses",
u"If selected, the system will send all analyses back to the "
u"referring laboratory for results update after verification, "
u"those that weren't requested through the shipment included. "
u"Otherwise, the system will send notifications back only for "
u"those analyses that were initially requested."
),
default=False,
required=False,
)

create_reference_analyses = schema.Bool(
title=_(
u"label_referral_create_reference_analyses",
u"Create analyses from reference laboratory"
),
description=_(
u"description_referral_create_reference_analyses",
u"If selected, the system will create missing analyses in the "
u"referring laboratory when receiving a notification for results "
u"update from the reference laboratory. Otherwise, the system "
u"will skip results for analyses that do not exist in the "
u"referred sample."
),
default=False,
required=False,
)


class ReferralControlPanelForm(RegistryEditForm):
schema = IReferralControlPanel
Expand Down
37 changes: 31 additions & 6 deletions src/senaite/referral/jsonapi/outboundsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@
from senaite.core.workflow import ANALYSIS_WORKFLOW
from senaite.jsonapi.exceptions import APIError
from senaite.jsonapi.interfaces import IPushConsumer
from senaite.referral.utils import get_create_reference_analyses
from senaite.referral.utils import get_services_mapping
from zope.interface import alsoProvides
from zope.interface import implementer

from bika.lims import api
from bika.lims.catalog import CATALOG_ANALYSIS_REQUEST_LISTING
from bika.lims.interfaces import ISubmitted
from bika.lims.utils import changeWorkflowState
from bika.lims.utils.analysis import create_analysis
from bika.lims.workflow import doActionFor
from senaite.referral import logger

Expand Down Expand Up @@ -84,15 +87,37 @@ def process(self):

# TODO Performance - convert to queue task

# Get the analyses that are in a suitable status grouped by keyword
statuses = ["referred", "assigned", "unassigned"]
by_keyword = self.get_analyses_by_keyword(sample, statuses)
# Get the analyses grouped by keyword
by_keyword = self.get_analyses_by_keyword(sample)

# Allowed statuses
statuses = dict.fromkeys(["referred", "assigned", "unassigned"], True)

# Do we need to create non-existing analyses
create_missing = get_create_reference_analyses()
services = get_services_mapping() if create_missing else {}

# Update the analyses passed-in
analysis_records = sample_record.get("analyses")
for analysis_record in analysis_records:
keyword = analysis_record.get("keyword")
for analysis in by_keyword.get(keyword):

# pop the analyses to be updated for the given keyword
analyses = by_keyword.get(keyword, [])
if not analyses:
service_uid = services.get(keyword)
service = api.get_object(service_uid, default=None)
if service:
# create the missing analysis
analyses = [create_analysis(sample, service)]

for analysis in analyses:
# skip if status is not valid
status = api.get_review_status(analysis)
if not statuses.get(status, False):
continue

# update the analysis
try:
self.update_analysis(analysis, analysis_record)
except Exception as e:
Expand All @@ -101,11 +126,11 @@ def process(self):

return True

def get_analyses_by_keyword(self, sample, statuses):
def get_analyses_by_keyword(self, sample):
"""Returns the analyses of the sample grouped by keyword
"""
groups = {}
analyses = sample.getAnalyses(full_objects=True, review_state=statuses)
analyses = sample.getAnalyses(full_objects=True)
for analysis in analyses:
keyword = analysis.getKeyword()
groups.setdefault(keyword, []).append(analysis)
Expand Down
2 changes: 1 addition & 1 deletion src/senaite/referral/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
dependencies before installing this add-on own profile.
-->
<metadata>
<version>2005</version>
<version>2006</version>

<!-- Be sure to install the following dependencies if not yet installed -->
<dependencies>
Expand Down
23 changes: 13 additions & 10 deletions src/senaite/referral/remotelab.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@
from bika.lims.interfaces import IAnalysisRequest
from bika.lims.utils import format_supsub
from bika.lims.utils.analysis import format_uncertainty
from remotesession import RemoteSession
from requests.auth import HTTPBasicAuth
from senaite.app.supermodel import SuperModel
from senaite.core.api.dtime import date_to_string
from senaite.referral import logger
from senaite.referral.interfaces import IExternalLaboratory
from senaite.referral.notifications import get_post_base_info
from senaite.referral.notifications import save_post
from senaite.referral.remotesession import RemoteSession
from senaite.referral.utils import get_lab_code
from senaite.referral.utils import get_notify_all_analyses
from senaite.referral.utils import get_user_info
from senaite.referral.utils import is_valid_url

Expand Down Expand Up @@ -190,30 +191,32 @@ def update_analyses(self, sample, timeout=5):
"""

def get_valid_analyses(sample):
# 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 = {
# Get the analyses to notify about to the reference laboratory,
# sorted by id descending to prioritize newest results if retests
query = {
"full_objects": True,
"getServiceUID": services,
"sort_on": "id",
"sort_order": "ascending",
}

notify_all = get_notify_all_analyses()
if not notify_all:
# only notify about analyses that were requested via shipment
inbound_sample = sample.getInboundSample()
query["getServiceUID"] = inbound_sample.getRawServices()

# 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):
for analysis in sample.getAnalyses(**query):

# Skip analyses not in a suitable status
if api.get_review_status(analysis) not in valid:
continue

# Skip retested, only interested in final results
if analysis.getRetest():
if analysis.getRawRetest():
continue

keyword = analysis.getKeyword()
Expand Down
8 changes: 8 additions & 0 deletions src/senaite/referral/upgrade/v02_00_000.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,11 @@ def setup_inbound_services(tool):
obj._p_deactivate()

logger.info("Setup inbound services [DONE]")


def setup_results_notification(tool):
logger.info("Setup results notification settings ...")
portal = tool.aq_inner.aq_parent
setup = portal.portal_setup
setup.runImportStepFromProfile(profile, "plone.app.registry")
logger.info("Setup results notification settings [DONE]")
12 changes: 10 additions & 2 deletions src/senaite/referral/upgrade/v02_00_000.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@
i18n_domain="senaite.referral">

<genericsetup:upgradeStep
title="SENAITE.REFERRAL 1.0.0: Store service uids in inbound sample"
title="SENAITE.REFERRAL 2.0.0: Setup results notification settings"
description="Setup results notification settings"
source="2005"
destination="2006"
handler=".v02_00_000.setup_results_notification"
profile="senaite.referral:default"/>

<genericsetup:upgradeStep
title="SENAITE.REFERRAL 2.0.0: Store service uids in inbound sample"
description="Store service uids in inbound sample"
source="2004"
destination="2005"
handler=".v02_00_000.setup_inbound_services"
profile="senaite.referral:default"/>

<genericsetup:upgradeStep
title="SENAITE.REFERRAL 1.0.0: New transition: 'Receive at reference'"
title="SENAITE.REFERRAL 2.0.0: New transition: 'Receive at reference'"
description="Added the transition 'receive_at_reference'"
source="2003"
destination="2004"
Expand Down
16 changes: 16 additions & 0 deletions src/senaite/referral/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,3 +335,19 @@ def search_sample_type(term, full_object=False):
if uid and full_object:
return api.get_object_by_uid(uid)
return uid


def get_notify_all_analyses():
"""Returns whether the system has to send notifications for analyses that
weren't initially requested
"""
key = "{}.notify_all_analyses".format(PRODUCT_NAME)
return api.get_registry_record(key, default=False)


def get_create_reference_analyses():
"""Returns whether the system has to create analyses if results are
notified by reference lab, but the sample does not have them
"""
key = "{}.create_reference_analyses".format(PRODUCT_NAME)
return api.get_registry_record(key, default=False)

0 comments on commit 9785b5d

Please sign in to comment.