Skip to content

Commit

Permalink
Allow to flag patients as deceased (#98)
Browse files Browse the repository at this point in the history
* Added deceased field to Patient content type

* Add deceased index

* Added deceased filter in patients listing

* Changelog

* Localize death dagger symbol

* Reuse function translate from core

* Better spelling

---------

Co-authored-by: Ramon Bartl <rb@ridingbytes.com>
  • Loading branch information
xispa and ramonski authored Jan 12, 2024
1 parent e0f7fee commit 3102e6f
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 23 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Changelog
1.5.0 (unreleased)
------------------

- #98 Allow to flag patients as deceased


1.4.0 (2023-01-10)
------------------
Expand Down
30 changes: 21 additions & 9 deletions src/senaite/patient/browser/patientfolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@

import collections
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_image
from bika.lims.utils import get_link
from senaite.app.listing.view import ListingView
from senaite.core.api import dtime
from senaite.patient import messageFactory as _sp
from senaite.patient import messageFactory as _
from senaite.patient.api import to_identifier_type_name
from senaite.patient.api import tuplify_identifiers
from senaite.patient.catalog import PATIENT_CATALOG
Expand Down Expand Up @@ -67,7 +66,7 @@ def __init__(self, context, request):
self.icon = "{}/{}".format(
self.portal_url, "senaite_theme/icon/patientfolder")

self.title = _sp("Patients")
self.title = _("Patients")
self.description = self.context.Description()
self.show_select_column = True
self.pagesize = 25
Expand Down Expand Up @@ -110,6 +109,11 @@ def __init__(self, context, request):
"title": _("Inactive"),
"contentFilter": {'is_active': False},
"columns": self.columns.keys(),
}, {
"id": "deceased",
"title": _("Deceased"),
"contentFilter": {'patient_deceased': True},
"columns": self.columns.keys(),
}, {
"id": "all",
"title": _("All"),
Expand Down Expand Up @@ -159,7 +163,7 @@ def folderitem(self, obj, item, index):
mrn = obj.getMRN()
if not mrn:
item["before"]["mrn"] = get_image("info", width=16)
mrn = t(_sp("mrn_not_defined", default="Not defined"))
mrn = t(_("mrn_not_defined", default="Not defined"))

item["mrn"] = self.to_utf8(mrn)
item["replace"]["mrn"] = get_link(url, value=mrn)
Expand All @@ -170,11 +174,19 @@ def folderitem(self, obj, item, index):
self.get_identifier_tags(identifiers))

# Fullname
fullname = obj.getFullname()
if fullname:
fullname = api.safe_unicode(fullname).encode("utf8")
item["fullname"] = fullname
item["replace"]["fullname"] = get_link(url, value=fullname)
fullname_nd = t(_("fullname_not_defined", default="Not defined"))
fullname = obj.getFullname() or fullname_nd
fullname = api.safe_unicode(fullname).encode("utf8")
item["fullname"] = fullname

# Death dagger
if obj.getDeceased():
fullname = t(_(
"patient_fullname_deceased_html",
default="${fullname} <sup>&dagger;</sup>",
mapping={"fullname": fullname}
))
item["replace"]["fullname"] = get_link(url, value=fullname)

# Email
email = obj.getEmail()
Expand Down
1 change: 1 addition & 0 deletions src/senaite/patient/catalog/indexer/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
<adapter name="patient_fullname" factory=".patient.patient_fullname" />
<adapter name="patient_searchable_text" factory=".patient.patient_searchable_text" />
<adapter name="patient_searchable_mrn" factory=".patient.patient_searchable_mrn" />
<adapter name="patient_deceased" factory=".patient.patient_deceased" />

</configure>
7 changes: 7 additions & 0 deletions src/senaite/patient/catalog/indexer/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ def patient_birthdate(instance):
return birthdate


@indexer(IPatient)
def patient_deceased(instance):
"""Index deceased
"""
return instance.getDeceased()


@indexer(IPatient)
def patient_searchable_text(instance):
"""Index for searchable text queries
Expand Down
1 change: 1 addition & 0 deletions src/senaite/patient/catalog/patient_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
("patient_birthdate", "", "DateIndex"),
("patient_searchable_text", "", "ZCTextIndex"),
("patient_searchable_mrn", "", "ZCTextIndex"),
("patient_deceased", "", "BooleanIndex"),
]

COLUMNS = BASE_COLUMNS + [
Expand Down
25 changes: 25 additions & 0 deletions src/senaite/patient/content/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,17 @@ class IPatientSchema(model.Schema):
required=False,
)

deceased = schema.Bool(
title=_(
u"label_patient_deceased",
default=u"Deceased"),
description=_(
u"description_patient_deceased",
default=u"Select this option if the patient is deceased"),
required=False,
default=False,
)

@invariant
def validate_mrn(data):
"""Checks if the patient MRN # is unique
Expand Down Expand Up @@ -732,3 +743,17 @@ def getFormattedAddress(self, atype=PHYSICAL_ADDRESS):
output = Template(address_format).safe_substitute(record)
output = filter(None, output.split(", "))
return ", ".join(output)

@security.protected(permissions.View)
def getDeceased(self):
"""Returns whether the patient is deceased
"""
accessor = self.accessor("deceased")
return accessor(self)

@security.protected(permissions.ModifyPortalContent)
def setDeceased(self, value):
"""Set if the patient deceased
"""
mutator = self.mutator("deceased")
return mutator(self, value)
15 changes: 2 additions & 13 deletions src/senaite/patient/i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,11 @@
# Copyright 2020-2024 by it's authors.
# Some rights reserved, see README and LICENSE.

from bika.lims import api
from senaite.core.i18n import translate as core_translate


def translate(msgid, **kwargs):
"""Translate any zope i18n msgid returned from MessageFactory
"""
msgid = api.safe_unicode(msgid)

# XX: If the msgid is from type `Message`, Zope's i18n translate tool gives
# priority `Message.domain` over the domain passed through kwargs
domain = kwargs.pop("domain", "senaite.patient")
params = {
"domain": getattr(msgid, "domain", domain),
"context": api.get_request(),
}
params.update(kwargs)

ts = api.get_tool("translation_service")
return ts.translate(msgid, **params)
return core_translate(msgid, domain=domain, **kwargs)
2 changes: 1 addition & 1 deletion src/senaite/patient/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<metadata>
<version>1500</version>
<version>1501</version>
<dependencies>
<dependency>profile-senaite.lims:default</dependency>
</dependencies>
Expand Down
13 changes: 13 additions & 0 deletions src/senaite/patient/upgrade/v01_05_000.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from senaite.core.upgrade.utils import UpgradeUtils
from senaite.patient import logger
from senaite.patient.config import PRODUCT_NAME
from senaite.patient.setuphandlers import setup_catalogs

version = "1.5.0"
profile = "profile-{0}:default".format(PRODUCT_NAME)
Expand All @@ -46,3 +47,15 @@ def upgrade(tool):

logger.info("{0} upgraded to version {1}".format(PRODUCT_NAME, version))
return True


def upgrade_catalog_indexes(tool):
"""Reinstall controlpanel registry
:param tool: portal_setup tool
"""
logger.info("Upgrade catalog indexes ...")
portal = tool.aq_inner.aq_parent
# setup patient catalog to add new indexes
setup_catalogs(portal)
logger.info("Upgrade catalog indexes [DONE]")
12 changes: 12 additions & 0 deletions src/senaite/patient/upgrade/v01_05_000.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup">

<!-- 1501: Allow to flag patients as deceased -->
<genericsetup:upgradeStep
title="Allow to flag patients as deceased"
description="
This upgrade step adds the field Deceased for patient content type, as
well as a new index 'patient_deceased' to allows to filter deceased
patients in patients listing."
source="1500"
destination="1501"
handler=".v01_05_000.upgrade_catalog_indexes"
profile="senaite.patient:default"/>

<genericsetup:upgradeStep
title="Upgrade to SENAITE.PATIENT 1.5.0"
source="1416"
Expand Down

0 comments on commit 3102e6f

Please sign in to comment.