Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow client local patients #68

Merged
merged 7 commits into from
May 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog
1.4.0 (unreleased)
------------------

- #68 Allow client local patients
- #66 Fix widget view mode
- #65 Fix cannot create partitions from samples with Patient assigned
- #64 Fix samples without patient middle name
Expand Down
60 changes: 58 additions & 2 deletions src/senaite/patient/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,31 @@
# Some rights reserved, see README and LICENSE.

import re
from datetime import datetime

from bika.lims import api
from bika.lims.utils import tmpID
from dateutil.relativedelta import relativedelta
from senaite.patient.config import PATIENT_CATALOG
from zope.component import getUtility
from zope.component.interfaces import IFactory
from zope.event import notify
from zope.lifecycleevent import ObjectCreatedEvent
from dateutil.relativedelta import relativedelta
from datetime import datetime

CLIENT_TYPE = "Client"
PATIENT_TYPE = "Patient"
CLIENT_VIEW_ID = "patients"
CLIENT_VIEW_ACTION = {
"id": CLIENT_VIEW_ID,
"name": "Patients",
"action": "string:${object_url}/patients",
"permission": "View",
"category": "object",
"visible": True,
"icon_expr": "",
"link_target": "",
"condition": "",
}

_marker = object()

Expand Down Expand Up @@ -277,3 +292,44 @@ def to_identifier_type_name(identifier_type_key):
name = record.get("value")

return name


def allow_patients_in_clients(allow=True):
"""Allow patient creation in patients
"""
pt = api.get_tool("portal_types")
# get the Client Type Info
ti = pt.getTypeInfo(CLIENT_TYPE)
# get the Client FTI
fti = pt.get(CLIENT_TYPE)
# get the current allowed types
allowed_types = set(fti.allowed_content_types)
# get the current actions
action_ids = map(lambda a: a.id, ti._actions)

# Enable / Disable Patient
if allow:
allowed_types.add(PATIENT_TYPE)
if CLIENT_VIEW_ID not in action_ids:
ti.addAction(**CLIENT_VIEW_ACTION)
# move before contacts
ref_index = action_ids.index("contacts")
actions = ti._cloneActions()
action = actions.pop()
actions.insert(ref_index - 1, action)
ti._actions = tuple(actions)
else:
allowed_types.discard(PATIENT_TYPE)
if CLIENT_VIEW_ID in action_ids:
ti.deleteActions([action_ids.index(CLIENT_VIEW_ID)])

# set the new types
fti.allowed_content_types = tuple(allowed_types)


def is_patient_allowed_in_client():
"""Returns wether patients can be created in clients or not
"""
allowed = api.get_registry_record(
"senaite.patient.allow_patients_in_clients", False)
return allowed
Empty file.
14 changes: 14 additions & 0 deletions src/senaite/patient/browser/client/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">

<!-- Patients View -->
<browser:page
name="patients"
for="bika.lims.interfaces.IClient"
class=".patients.PatientsView"
permission="zope2.View"
/>

</configure>
16 changes: 16 additions & 0 deletions src/senaite/patient/browser/client/patients.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-

from senaite.patient.browser.patientfolder import PatientFolderView
from senaite.patient.api import is_patient_allowed_in_client


class PatientsView(PatientFolderView):
"""Client local patients
"""

def __init__(self, context, request):
super(PatientsView, self).__init__(context, request)

# remove add action
if not is_patient_allowed_in_client():
self.context_actions = {}
1 change: 1 addition & 0 deletions src/senaite/patient/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
i18n_domain="senaite.patient">

<!-- Package includes -->
<include package=".client"/>
<include package=".patient"/>
<include package=".theme"/>
<include package=".viewlets"/>
Expand Down
6 changes: 6 additions & 0 deletions src/senaite/patient/browser/controlpanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class IPatientControlPanel(Interface):
description=_(""),
fields=[
"share_patients",
"allow_patients_in_clients",
],
)

Expand Down Expand Up @@ -372,6 +373,11 @@ class IPatientControlPanel(Interface):
u"from same client the sample belongs to")
)

allow_patients_in_clients = schema.Bool(
title=_(u"Allow patients in clients"),
description=_(u"If selected, patients can be created inside clients.")
)

@invariant
def validate_identifiers(data):
"""Checks if the keyword is unique and valid
Expand Down
19 changes: 17 additions & 2 deletions src/senaite/patient/browser/patientfolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@

from bika.lims import api
from bika.lims import senaiteMessageFactory as _
from bika.lims.interfaces import IClient
from bika.lims.utils import get_email_link
from bika.lims.utils import get_link
from senaite.app.listing.view import ListingView
from senaite.patient import messageFactory as _sp
from senaite.patient.catalog import PATIENT_CATALOG
from senaite.patient.api import to_identifier_type_name
from senaite.patient.api import tuplify_identifiers
from senaite.patient.catalog import PATIENT_CATALOG


class PatientFolderView(ListingView):
Expand All @@ -43,7 +44,10 @@ def __init__(self, context, request):
self.contentFilter = {
"portal_type": "Patient",
"path": {
"query": api.get_path(context),
"query": [
api.get_path(context),
api.get_path(self.portal.clients),
],
"level": 0
},
"sort_on": "created",
Expand Down Expand Up @@ -90,6 +94,9 @@ def __init__(self, context, request):
("birthdate", {
"title": _("Birthdate"),
"index": "patient_birthdate"}),
("folder", {
"title": _("Folder"),
"index": "path"}),
))

self.review_states = [
Expand Down Expand Up @@ -199,4 +206,12 @@ def folderitem(self, obj, item, index):
if birthdate:
item["birthdate"] = self.ulocalized_time(birthdate, long_format=0)

# Folder
parent = api.get_parent(obj)
parent_url = api.get_url(parent)
if IClient.providedBy(parent):
parent_url += "/@@patients"
item["folder"] = parent.Title()
item["replace"]["folder"] = get_link(parent_url, value=parent.Title())

return item
2 changes: 1 addition & 1 deletion src/senaite/patient/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>1406</version>
<version>1407</version>

<!-- Be sure to install the following dependencies if not yet installed -->
<dependencies>
Expand Down
6 changes: 6 additions & 0 deletions src/senaite/patient/subscribers/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,10 @@
handler=".patient.on_before_transition"
/>

<subscriber
for="senaite.patient.browser.controlpanel.IPatientControlPanel
zope.lifecycleevent.interfaces.IObjectModifiedEvent"
handler=".controlpanel.on_patient_settings_changed"
/>

</configure>
10 changes: 10 additions & 0 deletions src/senaite/patient/subscribers/controlpanel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-

from senaite.patient.api import allow_patients_in_clients


def on_patient_settings_changed(object, event):
"""Event handler when the patient settings changed
"""
allow = object.allow_patients_in_clients
allow_patients_in_clients(allow)
3 changes: 3 additions & 0 deletions src/senaite/patient/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def setUpZope(self, app, configurationContext):
super(SimpleTestLayer, self).setUpZope(app, configurationContext)

import bika.lims
import senaite.lims
import senaite.core
import senaite.app.listing
import senaite.impress
Expand All @@ -46,6 +47,7 @@ def setUpZope(self, app, configurationContext):

# Load ZCML
self.loadZCML(package=bika.lims)
self.loadZCML(package=senaite.lims)
self.loadZCML(package=senaite.core)
self.loadZCML(package=senaite.app.listing)
self.loadZCML(package=senaite.impress)
Expand All @@ -54,6 +56,7 @@ def setUpZope(self, app, configurationContext):

# Install product and call its initialize() function
zope.installProduct(app, "bika.lims")
zope.installProduct(app, "senaite.lims")
zope.installProduct(app, "senaite.core")
zope.installProduct(app, "senaite.app.listing")
zope.installProduct(app, "senaite.impress")
Expand Down
13 changes: 13 additions & 0 deletions src/senaite/patient/upgrade/v01_04_000.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,16 @@ def fix_samples_without_middlename(tool):
obj._p_deactivate()

logger.info("Fix samples without middle name [DONE]")


def allow_patients_in_clients(tool):
"""Allow to create patients inside clients
"""
logger.info("Allow patients in clients ...")

# import registry for controlpanel
portal = tool.aq_inner.aq_parent
setup = portal.portal_setup
setup.runImportStepFromProfile(profile, "plone.app.registry")

logger.info("Allow patients in clients [DONE]")
9 changes: 9 additions & 0 deletions src/senaite/patient/upgrade/v01_04_000.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup">

<!-- 1407: Patients inside clients -->
<genericsetup:upgradeStep
title="SENAITE PATIENT 1.4.0: Allow patients in clients"
description="Allow to create patients in the context of a client"
source="1406"
destination="1407"
handler="senaite.patient.upgrade.v01_04_000.allow_patients_in_clients"
profile="senaite.patient:default"/>

<!-- 1406: Fix samples without patient middle name -->
<genericsetup:upgradeStep
title="SENAITE PATIENT 1.4.0: Fix samples without patient middle name"
Expand Down