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.