From 44c4ba087c450a8a0da0e3df8e4dc1a7116234fa Mon Sep 17 00:00:00 2001 From: Luthando Ndlela Date: Wed, 27 Aug 2025 15:27:00 +0200 Subject: [PATCH 1/4] Add number of samples in batch column --- src/bika/lims/browser/batchfolder.py | 5 +++++ src/bika/lims/content/batch.py | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/bika/lims/browser/batchfolder.py b/src/bika/lims/browser/batchfolder.py index c44bcc8c6d..3ca8432131 100644 --- a/src/bika/lims/browser/batchfolder.py +++ b/src/bika/lims/browser/batchfolder.py @@ -83,6 +83,8 @@ def __init__(self, context, request): ("ClientBatchID", { "title": _("Client Batch ID"), "index": "getClientBatchID", }), + ("getNumberOfSamples", { + "title": _("Samples"), }), ("state_title", { "title": _("State"), "sortable": False, }), @@ -206,6 +208,9 @@ def folderitem(self, obj, item, index): item["BatchDate"] = self.ulocalized_time(date, long_format=True) item["BatchLabels"] = "" + item["getNumberOfSamples"] = str( + obj.getNumberOfSamples()) + if batch_labels: item["BatchLabels"] = ",".join(batch_labels) item["replace"]["BatchLabels"] = "".join(map( diff --git a/src/bika/lims/content/batch.py b/src/bika/lims/content/batch.py index 833022ab62..89bd35ab5e 100644 --- a/src/bika/lims/content/batch.py +++ b/src/bika/lims/content/batch.py @@ -270,5 +270,14 @@ def getProgress(self): total_progress = sum(sample_progresses) / total return total_progress + def getNumberOfSamples(self): + """ + Returns the number of samples. + :returns: number of samples + :rtype: integer + """ + samples = self.getAnalysisRequests() + return len(samples) + registerType(Batch, PROJECTNAME) From 41d8a94a0b411c11a568198a783c5a08ef032181 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Sun, 7 Jun 2026 13:14:27 +0200 Subject: [PATCH 2/4] Prevent duplicate "City" labels for countries with mixed subdivision types --- src/senaite/core/api/geo.py | 9 +++++++++ src/senaite/core/z3cform/widgets/address.py | 11 ++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/senaite/core/api/geo.py b/src/senaite/core/api/geo.py index a1cb526c21..27b7d8efe9 100644 --- a/src/senaite/core/api/geo.py +++ b/src/senaite/core/api/geo.py @@ -171,6 +171,15 @@ def get_subdivisions(thing, default=_marker): # Sort by code return sorted(subdivisions, key=lambda s: s.code) +def get_subdivision_type(subdivisions, default): + if not subdivisions: + return default + + types = set([sub.type for sub in subdivisions]) + if len(types) == 1: + return subdivisions[0].type + + return default def get_country_or_subdivision(thing, default=_marker): """Returns the country or subdivision for the thing passed-in diff --git a/src/senaite/core/z3cform/widgets/address.py b/src/senaite/core/z3cform/widgets/address.py index 9dce21d597..38646f2d56 100644 --- a/src/senaite/core/z3cform/widgets/address.py +++ b/src/senaite/core/z3cform/widgets/address.py @@ -235,9 +235,7 @@ def get_input_widget_attributes(self): subdivisions = geo.get_subdivisions(country, []) sub1[country] = map(lambda sub: sub.name, subdivisions) - label = _("State") - if subdivisions: - label = _(subdivisions[0].type) + label = geo.get_subdivision_type(subdivisions, _("State")) labels[country]["subdivision1"] = translate(label) subdivision1 = item.get("subdivision1") @@ -245,9 +243,7 @@ def get_input_widget_attributes(self): subdivisions = geo.get_subdivisions(subdivision1, []) sub2[subdivision1] = map(lambda sub: sub.name, subdivisions) - label = _("District") - if subdivisions: - label = _(subdivisions[0].type) + label = geo.get_subdivision_type(subdivisions, _("District")) labels[country]["subdivision2"] = translate(label) attributes = { @@ -305,12 +301,13 @@ def __call__(self): # Extract the subdivisions for this parent parent = safe_unicode(parent) items = geo.get_subdivisions(parent, default=[]) + subdivision_type = geo.get_subdivision_type(items, "State") def to_dict(subdivision): return { "name": subdivision.name, "code": subdivision.code, - "type": self.context.translate(_(subdivision.type)), + "type": self.context.translate(_(subdivision_type)), } return [to_dict(item) for item in items] From 97c4645c8bfbcba4ef21922fc16ff8058bf1e938 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Mon, 8 Jun 2026 08:12:41 +0200 Subject: [PATCH 3/4] Used getAnalysisRequestsBrains instead of getAnalysisRequests --- src/bika/lims/browser/batchfolder.py | 3 +-- src/bika/lims/content/batch.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bika/lims/browser/batchfolder.py b/src/bika/lims/browser/batchfolder.py index ec29d11a46..ea83656774 100644 --- a/src/bika/lims/browser/batchfolder.py +++ b/src/bika/lims/browser/batchfolder.py @@ -208,8 +208,7 @@ def folderitem(self, obj, item, index): item["BatchDate"] = self.ulocalized_time(date, long_format=True) item["BatchLabels"] = "" - item["getNumberOfSamples"] = str( - obj.getNumberOfSamples()) + item["getNumberOfSamples"] = str(obj.getNumberOfSamples()) if batch_labels: item["BatchLabels"] = ",".join(batch_labels) diff --git a/src/bika/lims/content/batch.py b/src/bika/lims/content/batch.py index 89bd35ab5e..f4987ae3bb 100644 --- a/src/bika/lims/content/batch.py +++ b/src/bika/lims/content/batch.py @@ -276,7 +276,7 @@ def getNumberOfSamples(self): :returns: number of samples :rtype: integer """ - samples = self.getAnalysisRequests() + samples = self.getAnalysisRequestsBrains() return len(samples) From 03f32572a9e60df05deec302290da9c20050c774 Mon Sep 17 00:00:00 2001 From: Lunga Baliwe Date: Mon, 8 Jun 2026 08:18:27 +0200 Subject: [PATCH 4/4] Revert "Prevent duplicate "City" labels for countries with mixed subdivision types" This reverts commit 41d8a94a0b411c11a568198a783c5a08ef032181. --- src/senaite/core/api/geo.py | 9 --------- src/senaite/core/z3cform/widgets/address.py | 11 +++++++---- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/senaite/core/api/geo.py b/src/senaite/core/api/geo.py index 27b7d8efe9..a1cb526c21 100644 --- a/src/senaite/core/api/geo.py +++ b/src/senaite/core/api/geo.py @@ -171,15 +171,6 @@ def get_subdivisions(thing, default=_marker): # Sort by code return sorted(subdivisions, key=lambda s: s.code) -def get_subdivision_type(subdivisions, default): - if not subdivisions: - return default - - types = set([sub.type for sub in subdivisions]) - if len(types) == 1: - return subdivisions[0].type - - return default def get_country_or_subdivision(thing, default=_marker): """Returns the country or subdivision for the thing passed-in diff --git a/src/senaite/core/z3cform/widgets/address.py b/src/senaite/core/z3cform/widgets/address.py index 38646f2d56..9dce21d597 100644 --- a/src/senaite/core/z3cform/widgets/address.py +++ b/src/senaite/core/z3cform/widgets/address.py @@ -235,7 +235,9 @@ def get_input_widget_attributes(self): subdivisions = geo.get_subdivisions(country, []) sub1[country] = map(lambda sub: sub.name, subdivisions) - label = geo.get_subdivision_type(subdivisions, _("State")) + label = _("State") + if subdivisions: + label = _(subdivisions[0].type) labels[country]["subdivision1"] = translate(label) subdivision1 = item.get("subdivision1") @@ -243,7 +245,9 @@ def get_input_widget_attributes(self): subdivisions = geo.get_subdivisions(subdivision1, []) sub2[subdivision1] = map(lambda sub: sub.name, subdivisions) - label = geo.get_subdivision_type(subdivisions, _("District")) + label = _("District") + if subdivisions: + label = _(subdivisions[0].type) labels[country]["subdivision2"] = translate(label) attributes = { @@ -301,13 +305,12 @@ def __call__(self): # Extract the subdivisions for this parent parent = safe_unicode(parent) items = geo.get_subdivisions(parent, default=[]) - subdivision_type = geo.get_subdivision_type(items, "State") def to_dict(subdivision): return { "name": subdivision.name, "code": subdivision.code, - "type": self.context.translate(_(subdivision_type)), + "type": self.context.translate(_(subdivision.type)), } return [to_dict(item) for item in items]