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

Remove getDueDate index and metadata #2601

Draft
wants to merge 7 commits into
base: 2.x
Choose a base branch
from
Draft
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
6 changes: 4 additions & 2 deletions src/bika/lims/browser/analyses/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ def __init__(self, context, request, **kwargs):
"sortable": False}),
("DueDate", {
"title": _("Due Date"),
"index": "getDueDate",
"sortable": False}),
("state_title", {
"title": _("Status"),
Expand Down Expand Up @@ -935,9 +934,12 @@ def _folder_item_duedate(self, analysis_brain, item):
# Note that if the analysis is a Reference Analysis, `getDueDate`
# returns the date when the ReferenceSample expires. If the analysis is
# a duplicate, `getDueDate` returns the due date of the source analysis
due_date = analysis_brain.getDueDate
obj = self.get_object(analysis_brain)
due_date = obj.getDueDate()
if not due_date:
# analysis has no TAT set or is not yet ready for process
return None

due_date_str = self.ulocalized_time(due_date, long_format=0)
item['DueDate'] = due_date_str

Expand Down
15 changes: 8 additions & 7 deletions src/bika/lims/browser/worksheet/views/add_analyses.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def __init__(self, context, request):
"index": "getDateReceived"}),
("getDueDate", {
"title": _("Due Date"),
"index": "getDueDate"}),
"index": "sortable_due_date"}),
))

self.review_states = [
Expand Down Expand Up @@ -268,21 +268,22 @@ def folderitem(self, obj, item, index):
the template
:index: current index of the item
"""
obj = api.get_object(obj)
received = obj.getDateReceived()
due_date = obj.getDueDate()

DueDate = obj.getDueDate
item["getDateReceived"] = self.ulocalized_time(received)
item["getDueDate"] = self.ulocalized_time(due_date)

item["getDateReceived"] = self.ulocalized_time(obj.getDateReceived)
item["getDueDate"] = self.ulocalized_time(DueDate)

if DueDate and DueDate < DateTime():
if due_date and due_date < DateTime():
item["after"]["DueDate"] = get_image(
"late.png", title=t(_("Late Analysis")))

# set category title
item["getCategoryTitle"] = self.get_category_title(obj)

# Add Priority column
priority_sort_key = obj.getPrioritySortkey
priority_sort_key = obj.getPrioritySortkey()
if not priority_sort_key:
# Default priority is Medium = 3.
# The format of PrioritySortKey is <priority>.<created>
Expand Down
39 changes: 18 additions & 21 deletions src/bika/lims/content/abstractroutineanalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,19 @@ def getClientOrderNumber(self):
@security.public
def getDateReceived(self):
"""Used to populate catalog values.
Returns the date the Analysis Request this analysis belongs to was
received. If the analysis was created after, then returns the date
the analysis was created.
Returns the date the Sample this analysis belongs to was received
"""
request = self.getRequest()
if request:
ar_date = request.getDateReceived()
if ar_date and self.created() > ar_date:
return self.created()
return ar_date
sample = self.getRequest()
if sample:
return sample.getDateReceived()
return None

@security.public
def isSampleReceived(self):
"""Returns whether if the Analysis Request this analysis comes from has
been received or not
"""
sample = self.getRequest()
if sample.getDateReceived():
if self.getDateReceived():
return True
return False

Expand Down Expand Up @@ -185,14 +179,18 @@ def isSampleSampled(self):

@security.public
def getStartProcessDate(self):
"""Returns the date time when the analysis request the analysis belongs
to was received. If the analysis request hasn't yet been received,
returns None
Overrides getStartProcessDateTime from the base class
:return: Date time when the analysis is ready to be processed.
"""Returns the date time when this analysis is considered ready for
testing. It returns the datetime when the sample the analysis belongs
to was received or when the analysis was created if after reception.
Returns None if the sample has not been received yet.
:return: Date time when the analysis is considered ready for testing
:rtype: DateTime
"""
return self.getDateReceived()
received = self.getDateReceived()
if not received:
return None
# return the analysis creation date if is after reception
return max([received, self.created()])

@security.public
def getSamplePoint(self):
Expand All @@ -203,10 +201,9 @@ def getSamplePoint(self):

@security.public
def getDueDate(self):
"""Used to populate getDueDate index and metadata.
This calculates the difference between the time the analysis processing
started and the maximum turnaround time. If the analysis has no
turnaround time set or is not yet ready for proces, returns None
"""This calculates the difference between the time the analysis
processing started and the maximum turnaround time. If the analysis has
no turnaround time set or is not yet ready for process, returns None
"""
tat = self.getMaxTimeAllowed()
if not tat:
Expand Down
19 changes: 15 additions & 4 deletions src/bika/lims/content/analysisrequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1713,10 +1713,21 @@ def getManagers(self):
return manager_list

def getDueDate(self):
"""Returns the earliest due date of the analyses this Analysis Request
contains."""
due_dates = map(lambda an: an.getDueDate, self.getAnalyses())
return due_dates and min(due_dates) or None
"""Returns the due date of this sample, that is the earliest due date
of the analyses it contains. Returns None if the sample has not been
received yet
"""
if not self.getDateReceived():
return None

analyses = self.getAnalyses(sort_on="sortable_due_date",
sort_order="ascending")
if not analyses:
return None

# return the due date of the earliest due analysis
analysis = api.get_object(analyses[0])
return analysis.getDueDate()

security.declareProtected(View, 'getLate')

Expand Down
10 changes: 6 additions & 4 deletions src/senaite/core/browser/samples/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ def __init__(self, context, request):
"to_be_verified",
"verified",
),
"getDueDate": {
"sortable_due_date": {
"query": DateTime(),
"range": "max",
},
Expand Down Expand Up @@ -545,10 +545,14 @@ def folderitem(self, obj, item, index):
# val = obj.Schema().getField('SubGroup').get(obj)
# item['SubGroup'] = val.Title() if val else ''

full_object = api.get_object(obj)

# due date
due_date = full_object.getDueDate()
item["SamplingDate"] = self.str_date(obj.getSamplingDate)
item["getDateSampled"] = self.str_date(obj.getDateSampled)
item["getDateReceived"] = self.str_date(obj.getDateReceived)
item["getDueDate"] = self.str_date(obj.getDueDate)
item["getDueDate"] = self.str_date(due_date)
item["getDatePublished"] = self.str_date(obj.getDatePublished)
item["getDateVerified"] = self.str_date(obj.getDateVerified)

Expand Down Expand Up @@ -579,7 +583,6 @@ def folderitem(self, obj, item, index):
after_icons += get_image("delete.png",
title=t(_("Results have been withdrawn")))

due_date = obj.getDueDate
if due_date and due_date < (obj.getDatePublished or DateTime()):
due_date_str = self.ulocalized_time(due_date)
img_title = "{}: {}".format(t(_("Late Analyses")), due_date_str)
Expand Down Expand Up @@ -622,7 +625,6 @@ def folderitem(self, obj, item, index):
if item["review_state"] == "to_be_sampled":
# We need to get the full object in order to check
# the permissions
full_object = api.get_object(obj)
if check_permission(TransitionSampleSample, full_object):
# make fields required and editable
item["required"] = ["getSampler", "getDateSampled"]
Expand Down
3 changes: 1 addition & 2 deletions src/senaite/core/catalog/analysis_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
("getClientTitle", "", "FieldIndex"),
("getClientUID", "", "FieldIndex"),
("getDateReceived", "", "DateIndex"),
("getDueDate", "", "DateIndex"),
("getInstrumentUID", "", "FieldIndex"),
("getKeyword", "", "FieldIndex"),
("getPointOfCapture", "", "FieldIndex"),
Expand All @@ -48,6 +47,7 @@
("getServiceUID", "", "FieldIndex"),
("getWorksheetUID", "", "FieldIndex"),
("sortable_title", "", "FieldIndex"),
("sortable_due_date", "", "DateIndex"),
]

COLUMNS = BASE_COLUMNS + [
Expand All @@ -58,7 +58,6 @@
"getClientURL",
"getDateReceived",
"getDateSampled",
"getDueDate",
"getKeyword",
"getLastVerificator",
"getMethodTitle",
Expand Down
2 changes: 2 additions & 0 deletions src/senaite/core/catalog/indexer/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
<adapter name="assigned_state" factory=".sample.assigned_state"/>
<adapter name="is_received" factory=".sample.is_received"/>
<adapter name="listing_searchable_text" factory=".sample.listing_searchable_text"/>
<adapter name="sortable_due_date" factory=".sample.sortable_due_date"/>

<!-- Request Analysis Indexer -->
<adapter name="getAncestorsUIDs" factory=".requestanalysis.getAncestorsUIDs"/>
<adapter name="sortable_due_date" factory=".requestanalysis.sortable_due_date"/>

<!-- AnalysisCategory Indexer -->
<adapter name="sortable_title" factory=".analysiscategory.sortable_title"/>
Expand Down
24 changes: 24 additions & 0 deletions src/senaite/core/catalog/indexer/requestanalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@
# Copyright 2018-2024 by it's authors.
# Some rights reserved, see README and LICENSE.

from datetime import datetime
from datetime import timedelta

from bika.lims import api
from bika.lims.interfaces.analysis import IRequestAnalysis
from plone.indexer import indexer
from senaite.core.api import dtime


@indexer(IRequestAnalysis)
Expand All @@ -31,3 +35,23 @@ def getAncestorsUIDs(instance):
request = instance.getRequest()
parents = map(lambda ar: api.get_uid(ar), request.getAncestors())
return [api.get_uid(request)] + parents


@indexer(IRequestAnalysis)
def sortable_due_date(instance):
"""Returns the due date of the analysis, but without taking workdays into
account. This is a hint for sorting by due date, but it's value might not
match with the real due date.
"""
tat = instance.getMaxTimeAllowed()
if not tat:
return dtime.to_DT(datetime.max)

start = instance.getStartProcessDate()
if not start:
return dtime.to_DT(datetime.max)

start = dtime.to_dt(start)
tat = api.to_minutes(**tat)
due_date = start + timedelta(minutes=tat)
return dtime.to_DT(due_date)
16 changes: 16 additions & 0 deletions src/senaite/core/catalog/indexer/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from senaite.core.catalog import SAMPLE_CATALOG
from senaite.core.interfaces import ISampleCatalog
from zope.component import getAdapters
from senaite.core.catalog.indexer import requestanalysis


@indexer(IAnalysisRequest)
Expand Down Expand Up @@ -148,3 +149,18 @@ def listing_searchable_text(instance):
entries = filter(None, entries)

return u" ".join(map(api.safe_unicode, entries))


@indexer(IAnalysisRequest)
def sortable_due_date(instance):
"""Returns the earliest due date of the analyses that belong to this
instance, but without taking workdays into account. This is a hint for
sorting by due date, but it's value might not match with the real due date
"""
analyses = instance.getAnalyses(sort_on="sortable_due_date",
sort_order="ascending")
if not analyses:
return None

analysis = api.get_object(analyses[0])
return requestanalysis.sortable_due_date(analysis)()
3 changes: 1 addition & 2 deletions src/senaite/core/catalog/sample_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
("getDateSampled", "", "DateIndex"),
("getDateVerified", "", "DateIndex"),
("getDistrict", "", "FieldIndex"),
("getDueDate", "", "DateIndex"),
("getPrinted", "", "FieldIndex"),
("getPrioritySortkey", "", "FieldIndex"),
("getProvince", "", "FieldIndex"),
Expand All @@ -54,6 +53,7 @@
("listing_searchable_text", "", "ZCTextIndex"),
("modified", "", "DateIndex"),
("sortable_title", "", "FieldIndex"),
("sortable_due_date", "", "DateIndex"),
]

COLUMNS = BASE_COLUMNS + [
Expand All @@ -77,7 +77,6 @@
"getDateVerified",
"getDescendantsUIDs",
"getDistrict",
"getDueDate",
"getHazardous",
"getInternalUse",
"getInvoiceExclude",
Expand Down
1 change: 0 additions & 1 deletion src/senaite/core/catalog/senaite_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
("getClientUID", "", "FieldIndex"),
("getDateReceived", "", "DateIndex"),
("getDateSampled", "", "DateIndex"),
("getDueDate", "", "DateIndex"),
("getExpiryDate", "", "DateIndex"),
("getId", "", "FieldIndex"),
("getReferenceDefinitionUID", "", "FieldIndex"),
Expand Down
2 changes: 1 addition & 1 deletion src/senaite/core/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<metadata>
<version>2649</version>
<version>2650</version>
<dependencies>
<dependency>profile-Products.ATContentTypes:base</dependency>
<dependency>profile-Products.CMFEditions:CMFEditions</dependency>
Expand Down
19 changes: 19 additions & 0 deletions src/senaite/core/upgrade/v02_06_000.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from Products.Archetypes.utils import getRelURL
from Products.CMFCore.permissions import View
from senaite.core import logger
from senaite.core.api.catalog import del_column
from senaite.core.api.catalog import del_index
from senaite.core.api.catalog import reindex_index
from senaite.core.catalog import ANALYSIS_CATALOG
Expand Down Expand Up @@ -2465,3 +2466,21 @@ def remove_is_sample_received_index(tool):
cat = api.get_tool(ANALYSIS_CATALOG)
del_index(cat, "isSampleReceived")
logger.info("Removing isSampleReceived index from catalogs [DONE]")


def remove_get_due_date_index(tool):
logger.info("Removing getDueDate index from catalogs ...")
index = "getDueDate"
portal = tool.aq_inner.aq_parent
for cat in portal.objectValues():
if not isinstance(cat, BaseCatalog):
continue
logger.info("Removing getDueDate index from {}".format(cat.id))
del_index(cat, index)
logger.info("Removing getDueDate column from {}".format(cat.id))
del_column(cat, index)

# create the new indexes if necessary
setup_core_catalogs(portal)

logger.info("Removing getDueDate index from catalogs [DONE]")
8 changes: 8 additions & 0 deletions src/senaite/core/upgrade/v02_06_000.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
i18n_domain="senaite.core">

<genericsetup:upgradeStep
title="SENAITE.CORE 2.6.0: Remove getDueDate index"
description="Remove getDueDate index"
source="2649"
destination="2650"
handler=".v02_06_000.remove_get_due_date_index"
profile="senaite.core:default"/>

<genericsetup:upgradeStep
title="SENAITE.CORE 2.6.0: Remove isSampleReceived index"
description="Remove isSampleReceived index"
Expand Down
Loading