From 7f5cd8a08bbd2f308726212a730ba15455c2278f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Puiggen=C3=A9?= Date: Sun, 13 Dec 2020 14:28:51 +0100 Subject: [PATCH] Add "Automatic verification of samples" setting in setup When the setting is enabled (default), the sample automatically transitions to verified status as soon as all the analyses it contains are verified. Manual verification of sample is required otherwise, once all analyses have been verified. --- CHANGES.rst | 1 + src/bika/lims/content/bikasetup.py | 15 ++ src/bika/lims/workflow/analysis/events.py | 8 +- .../core/tests/doctests/SampleAutoVerify.rst | 136 ++++++++++++++++++ .../tests/doctests/WorksheetApplyTemplate.rst | 22 +-- 5 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 src/senaite/core/tests/doctests/SampleAutoVerify.rst diff --git a/CHANGES.rst b/CHANGES.rst index 3952582cc3..67397a1ddf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changelog 2.0.0rc3 (unreleased) --------------------- +- #1712 Add "Automatic verification of samples" setting in setup - #1711 Make attachments viewlet to rely on permissions, not on statuses - #1709 Remove "attachment_due" status from Worksheet and Sample - #1709 Consolidated Attachment Options to a single Option diff --git a/src/bika/lims/content/bikasetup.py b/src/bika/lims/content/bikasetup.py index c873044eb0..4356376f93 100644 --- a/src/bika/lims/content/bikasetup.py +++ b/src/bika/lims/content/bikasetup.py @@ -51,6 +51,7 @@ from Products.Archetypes.atapi import StringField from Products.Archetypes.atapi import TextAreaWidget from Products.Archetypes.atapi import registerType +from Products.Archetypes.Field import BooleanField from Products.Archetypes.Field import TextField from Products.Archetypes.utils import DisplayList from Products.Archetypes.utils import IntDisplayList @@ -342,6 +343,20 @@ def getCounterTypes(self, instance=None): ) ), ), + BooleanField( + "AutoVerifySamples", + schemata="Analyses", + default=True, + widget=BooleanWidget( + label=_("Automatic verification of samples"), + description=_( + "When enabled, the sample is automatically verified as soon as " + "all results are verified. Otherwise, users with enough " + "privileges have to manually verify the sample afterwards. " + "Default: enabled" + ) + ) + ), BooleanField( 'SelfVerificationEnabled', schemata="Analyses", diff --git a/src/bika/lims/workflow/analysis/events.py b/src/bika/lims/workflow/analysis/events.py index 935412f3f5..bee11ec337 100644 --- a/src/bika/lims/workflow/analysis/events.py +++ b/src/bika/lims/workflow/analysis/events.py @@ -222,9 +222,13 @@ def after_verify(analysis): doActionFor(ws, 'verify') push_reindex_to_actions_pool(ws) - # Promote transition to Analysis Request + # Promote transition to Analysis Request if Sample auto-verify is enabled if IRequestAnalysis.providedBy(analysis): - doActionFor(analysis.getRequest(), 'verify') + setup = api.get_setup() + if setup.getAutoVerifySamples(): + doActionFor(analysis.getRequest(), "verify") + + # Reindex the sample (and ancestors) this analysis belongs to reindex_request(analysis) diff --git a/src/senaite/core/tests/doctests/SampleAutoVerify.rst b/src/senaite/core/tests/doctests/SampleAutoVerify.rst new file mode 100644 index 0000000000..626a3ed296 --- /dev/null +++ b/src/senaite/core/tests/doctests/SampleAutoVerify.rst @@ -0,0 +1,136 @@ +Sample - Auto-verify +-------------------- + +When the setup setting "Automatic verification of Samples" is enabled, the +system automatically transitions the sample to "verified" status when all the +analyses it contains are verified. System expects the user to manually verify +the sample otherwise. + + +Test Setup +.......... + +Running this test from the buildout directory: + + bin/test -t SampleAutoVerify + +Needed Imports: + + >>> from bika.lims import api + >>> from bika.lims.utils.analysisrequest import create_analysisrequest + >>> from bika.lims.workflow import doActionFor as do_action_for + >>> from DateTime import DateTime + >>> from plone.app.testing import setRoles + >>> from plone.app.testing import TEST_USER_ID + +Functional Helpers: + + >>> def new_sample(services): + ... values = { + ... 'Client': client.UID(), + ... 'Contact': contact.UID(), + ... 'DateSampled': date_now, + ... 'SampleType': sampletype.UID()} + ... uids = map(api.get_uid, services) + ... sample = create_analysisrequest(client, request, values, uids) + ... transitioned = do_action_for(sample, "receive") + ... return sample + + >>> def submit_results(sample): + ... for analysis in sample.getAnalyses(full_objects=True): + ... analysis.setResult(10) + ... do_action_for(analysis, "submit") + + >>> def verify_results(sample): + ... analyses = sample.getAnalyses(full_objects=True) + ... map(lambda a: do_action_for(a, "verify"), analyses) + +Variables: + + >>> portal = self.portal + >>> request = self.request + >>> setup = portal.bika_setup + >>> date_now = DateTime().strftime("%Y-%m-%d") + + +Create some baseline objects for the test: + + >>> setRoles(portal, TEST_USER_ID, ['LabManager',]) + >>> client = api.create(portal.clients, "Client", Name="Happy Hills", ClientID="HH", MemberDiscountApplies=True) + >>> contact = api.create(client, "Contact", Firstname="Rita", Lastname="Mohale") + >>> sampletype = api.create(setup.bika_sampletypes, "SampleType", title="Water", Prefix="W") + >>> labcontact = api.create(setup.bika_labcontacts, "LabContact", Firstname="Lab", Lastname="Manager") + >>> department = api.create(setup.bika_departments, "Department", title="Chemistry", Manager=labcontact) + >>> category = api.create(setup.bika_analysiscategories, "AnalysisCategory", title="Metals", Department=department) + >>> Cu = api.create(setup.bika_analysisservices, "AnalysisService", title="Copper", Keyword="Cu", Price="15", Category=category.UID(), Accredited=True) + >>> Fe = api.create(setup.bika_analysisservices, "AnalysisService", title="Iron", Keyword="Fe", Price="10", Category=category.UID()) + >>> Au = api.create(setup.bika_analysisservices, "AnalysisService", title="Gold", Keyword="Au", Price="20", Category=category.UID()) + +Enable the self verification: + + >>> setup.setSelfVerificationEnabled(True) + >>> setup.getSelfVerificationEnabled() + True + +Sample auto-verification enabled +................................ + +This test validates that when "Automatic verification of Samples" setting is +enabled, the sample **does** transition automatically to "verified" status. + +Enable the automatic verification of samples: + + >>> setup.setAutoVerifySamples(True) + >>> setup.getAutoVerifySamples() + True + +Create a Sample, submit and verify results: + + >>> sample = new_sample([Cu, Fe, Au]) + >>> submit_results(sample) + >>> verify_results(sample) + +The status of the analyses is "verified": + + >>> map(api.get_review_status, sample.getAnalyses()) + ['verified', 'verified', 'verified'] + +And the status of the sample as well: + + >>> api.get_review_status(sample) + 'verified' + + +Sample auto-verification disabled +................................. + +This test validates that when "Automatic verification of Samples" setting is +disabled, the sample does not transition automatically to "verified" status. + +Disable the automatic verification of samples: + + >>> setup.setAutoVerifySamples(False) + >>> setup.getAutoVerifySamples() + False + +Create a Sample, submit and verify results: + + >>> sample = new_sample([Cu, Fe, Au]) + >>> submit_results(sample) + >>> verify_results(sample) + +The status of the analyses is "verified": + + >>> map(api.get_review_status, sample.getAnalyses()) + ['verified', 'verified', 'verified'] + +But the sample remains in "to_be_verified" status: + + >>> api.get_review_status(sample) + 'to_be_verified' + +Manual verification of the sample is required: + + >>> success = do_action_for(sample, "verify") + >>> api.get_review_status(sample) + 'verified' diff --git a/src/senaite/core/tests/doctests/WorksheetApplyTemplate.rst b/src/senaite/core/tests/doctests/WorksheetApplyTemplate.rst index ba6c78f352..306ad3d046 100644 --- a/src/senaite/core/tests/doctests/WorksheetApplyTemplate.rst +++ b/src/senaite/core/tests/doctests/WorksheetApplyTemplate.rst @@ -20,7 +20,7 @@ Worksheet. Test Setup ----------- +.......... Running this test from the buildout directory: @@ -138,7 +138,7 @@ layout with 7 slots: Apply Worksheet Template to a Worksheet ---------------------------------------- +....................................... Create a new Worksheet by using this worksheet template: @@ -219,7 +219,7 @@ slots reserved for blank and controls are not occupied: Remove analyses and Apply Worksheet Template again --------------------------------------------------- +.................................................. Remove analyses located at position 2: @@ -269,7 +269,7 @@ As well as in duplicate analyses: Remove a duplicate and add it manually --------------------------------------- +...................................... Remove all duplicate analyses from slot 5: @@ -337,7 +337,7 @@ control: Control and blanks with Worksheet Template ------------------------------------------- +.......................................... First, create a Reference Definition for blank: @@ -400,7 +400,7 @@ Control analyses at slot number 6: Remove Reference Analyses and add them manually ------------------------------------------------ +............................................... Remove all controls from slot 6: @@ -467,7 +467,7 @@ Reject any remaining analyses awaiting for assignment: WorksheetTemplate assignment to a non-empty Worksheet ------------------------------------------------------ +..................................................... Worksheet Template can also be used when the worksheet is not empty. The template has slots available for routine analyses in positions 1, 2 and 4: @@ -588,7 +588,7 @@ Reject any remaining analyses awaiting for assignment: WorksheetTemplate assignment keeps Sample natural order -------------------------------------------------------- +....................................................... Analyses are grabbed by using their priority sort key, but samples are sorted in natural order in the slots. @@ -611,7 +611,7 @@ Slots follows the natural order of the samples: Assignment of a WorksheetTemplate with no services --------------------------------------------------- +.................................................. Create a Worksheet Template without services assigned: @@ -646,7 +646,7 @@ Worksheet remains empty: Assignment of Worksheet Template with Instrument --------------------------------------------------- +................................................ When a Worksheet Template has an instrument assigned, only analyses that can be performed with that same instrument are added in the worksheet. @@ -744,7 +744,7 @@ Reject any remaining analyses awaiting for assignment: Assignment of Worksheet Template with Method --------------------------------------------- +............................................ When a Worksheet Template has a method assigned, only analyses that can be performed with that same method are added in the worksheet.