diff --git a/docs/changelog.rst b/docs/changelog.rst index 103d87e..71aaf43 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,8 @@ Changelog 1.5.0 (unreleased) ------------------ +- #98 Allow to flag patients as deceased + 1.4.0 (2023-01-10) ------------------ diff --git a/src/senaite/patient/browser/patientfolder.py b/src/senaite/patient/browser/patientfolder.py index 3187658..1bcde47 100644 --- a/src/senaite/patient/browser/patientfolder.py +++ b/src/senaite/patient/browser/patientfolder.py @@ -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 @@ -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 @@ -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"), @@ -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) @@ -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} ", + mapping={"fullname": fullname} + )) + item["replace"]["fullname"] = get_link(url, value=fullname) # Email email = obj.getEmail() diff --git a/src/senaite/patient/catalog/indexer/configure.zcml b/src/senaite/patient/catalog/indexer/configure.zcml index 1d2e26d..becf3b3 100644 --- a/src/senaite/patient/catalog/indexer/configure.zcml +++ b/src/senaite/patient/catalog/indexer/configure.zcml @@ -22,5 +22,6 @@ + diff --git a/src/senaite/patient/catalog/indexer/patient.py b/src/senaite/patient/catalog/indexer/patient.py index f08f13e..5f1497d 100644 --- a/src/senaite/patient/catalog/indexer/patient.py +++ b/src/senaite/patient/catalog/indexer/patient.py @@ -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 diff --git a/src/senaite/patient/catalog/patient_catalog.py b/src/senaite/patient/catalog/patient_catalog.py index 48d1bc7..2a3128b 100644 --- a/src/senaite/patient/catalog/patient_catalog.py +++ b/src/senaite/patient/catalog/patient_catalog.py @@ -42,6 +42,7 @@ ("patient_birthdate", "", "DateIndex"), ("patient_searchable_text", "", "ZCTextIndex"), ("patient_searchable_mrn", "", "ZCTextIndex"), + ("patient_deceased", "", "BooleanIndex"), ] COLUMNS = BASE_COLUMNS + [ diff --git a/src/senaite/patient/content/patient.py b/src/senaite/patient/content/patient.py index 5e1fa40..642f4e3 100644 --- a/src/senaite/patient/content/patient.py +++ b/src/senaite/patient/content/patient.py @@ -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 @@ -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) diff --git a/src/senaite/patient/i18n.py b/src/senaite/patient/i18n.py index c8c2359..1b90ba7 100644 --- a/src/senaite/patient/i18n.py +++ b/src/senaite/patient/i18n.py @@ -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) diff --git a/src/senaite/patient/profiles/default/metadata.xml b/src/senaite/patient/profiles/default/metadata.xml index c85d7a1..f6fbb24 100644 --- a/src/senaite/patient/profiles/default/metadata.xml +++ b/src/senaite/patient/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 1500 + 1501 profile-senaite.lims:default diff --git a/src/senaite/patient/upgrade/v01_05_000.py b/src/senaite/patient/upgrade/v01_05_000.py index a719638..5bdfaa1 100644 --- a/src/senaite/patient/upgrade/v01_05_000.py +++ b/src/senaite/patient/upgrade/v01_05_000.py @@ -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) @@ -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]") diff --git a/src/senaite/patient/upgrade/v01_05_000.zcml b/src/senaite/patient/upgrade/v01_05_000.zcml index e8eae53..2c5af6f 100644 --- a/src/senaite/patient/upgrade/v01_05_000.zcml +++ b/src/senaite/patient/upgrade/v01_05_000.zcml @@ -2,6 +2,18 @@ xmlns="http://namespaces.zope.org/zope" xmlns:genericsetup="http://namespaces.zope.org/genericsetup"> + + +