From b75f5c454db99037ee3ff3500db6b6264470f5b4 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Thu, 12 Oct 2023 22:36:39 -0500 Subject: [PATCH 01/27] allows app build with both parent-select and inline case search on the parent/child module --- corehq/apps/app_manager/helpers/validators.py | 15 --------------- .../app_manager/partials/build_errors.html | 12 ------------ 2 files changed, 27 deletions(-) diff --git a/corehq/apps/app_manager/helpers/validators.py b/corehq/apps/app_manager/helpers/validators.py index 9f4f980919aa..16369d875b91 100644 --- a/corehq/apps/app_manager/helpers/validators.py +++ b/corehq/apps/app_manager/helpers/validators.py @@ -411,21 +411,6 @@ def validate_parent_select(self): 'type': 'invalid parent select id', 'module': self.get_module_info(), }) - else: - module_id = self.module.parent_select.module_id - parent_select_module = self.module.get_app().get_module_by_unique_id(module_id) - if parent_select_module and module_uses_inline_search(parent_select_module): - errors.append({ - 'type': 'parent select is inline search module', - 'module': self.get_module_info(), - }) - - if module_uses_inline_search(self.module): - if self.module.parent_select.relationship: - errors.append({ - 'type': 'inline search parent select relationship', - 'module': self.get_module_info(), - }) return errors diff --git a/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html b/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html index bfc5b95cd596..70dddca3966e 100644 --- a/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html +++ b/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html @@ -197,18 +197,6 @@

uses "Display only forms" and is also configured with "make search input available after search". This workflow is unsupported. {% endblocktrans %} - {% case "parent select is inline search module" %} - {% blocktrans with module_name=error.module.name|trans:langs %} - {{ module_name }} - uses parent case selection but parent case list is using - "make search input available after search". This workflow is unsupported. - {% endblocktrans %} - {% case "inline search parent select relationship" %} - {% blocktrans with module_name=error.module.name|trans:langs %} - {{ module_name }} - uses parent case selection and is configured with - "make search input available after search". This workflow is unsupported. - {% endblocktrans %} {% case "circular case hierarchy" %} {% blocktrans with module_name=error.module.name|trans:langs %} The case hierarchy for {{ module_name }} contains a circular reference. From 85d0ba9fcc5908b0fc12e713e219b4f0d5ed3ce7 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Thu, 12 Oct 2023 22:41:06 -0500 Subject: [PATCH 02/27] feat: exclude cases already in local db from being claimed --- .../apps/app_manager/suite_xml/post_process/remote_requests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py index 679484addcf4..402fb0709f62 100644 --- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py +++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py @@ -153,6 +153,8 @@ def build_case_id_query_data(self): data.exclude = self._get_multi_select_exclude() else: data.ref = QuerySessionXPath(self.case_session_var).instance() + if not self.exclude_relevant: + data.exclude = CaseIDXPath(data.ref).case().count().neq(0) return data def _get_multi_select_nodeset(self): From 9337716eaaff3b47936efd3bd480eb19c4df397f Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Thu, 12 Oct 2023 22:50:01 -0500 Subject: [PATCH 03/27] feat: claims parent cases if parent select is configured and active for the module --- corehq/apps/app_manager/suite_xml/sections/entries.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index 05c51ab3558d..e9831070a6d3 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -247,6 +247,7 @@ def include_post_in_entry(self, module_id): def add_post_to_entry(self, form, module, e): from ..post_process.remote_requests import ( + QuerySessionXPath, RemoteRequestFactory, ) case_session_var = self.get_case_session_var_for_form(form) @@ -256,6 +257,14 @@ def add_post_to_entry(self, form, module, e): None, module, [], case_session_var=case_session_var, storage_instance=storage_instance, exclude_relevant=case_search_sync_cases_on_form_entry_enabled_for_domain(self.app.domain)) e.post = remote_request_factory.build_remote_request_post() + datum_ids = [form_datum.datum.id for form_datum in self.get_datum_meta_module(module, use_filter=True) + if form_datum.datum.id != case_session_var] + if hasattr(module, 'parent_select') and module.parent_select.active: + for datum_id in datum_ids: + data = QueryData(key='case_id') + data.ref = QuerySessionXPath(datum_id).instance() + data.exclude = CaseIDXPath(data.ref).case().count().neq(0) + e.post.data.append(data) def entry_for_module(self, module): # avoid circular dependency From af3e8330b5520aec4d788a39f3fcfcff150ab87c Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Fri, 10 Nov 2023 13:29:16 -0800 Subject: [PATCH 04/27] feat: adds validation that module and its parent select module has unique instance names --- corehq/apps/app_manager/helpers/validators.py | 13 +++++++++++++ .../app_manager/partials/build_errors.html | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/corehq/apps/app_manager/helpers/validators.py b/corehq/apps/app_manager/helpers/validators.py index 16369d875b91..c00298b96221 100644 --- a/corehq/apps/app_manager/helpers/validators.py +++ b/corehq/apps/app_manager/helpers/validators.py @@ -406,12 +406,25 @@ def validate_parent_select(self): from corehq.apps.app_manager.views.modules import get_all_case_modules valid_modules = get_all_case_modules(self.app, self.module) valid_module_ids = [info['unique_id'] for info in valid_modules] + search_config = getattr(self.module, 'search_config', None) if self.module.parent_select.module_id not in valid_module_ids: errors.append({ 'type': 'invalid parent select id', 'module': self.get_module_info(), }) + elif search_config: + parent_module_id = self.module.parent_select.module_id + parent_select_module = self.module.get_app().get_module_by_unique_id(parent_module_id) + if parent_select_module and module_uses_inline_search(parent_select_module): + parent_module_instance_name = parent_select_module.search_config.get_instance_name() + if search_config.get_instance_name() == parent_module_instance_name: + errors.append({ + 'type': 'non-unique instance name with parent select module', + "message": f'The instance "{search_config.get_instance_name()}" is not unique', + "module": self.get_module_info(), + "details": search_config.get_instance_name() + }) return errors def validate_smart_links(self): diff --git a/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html b/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html index 70dddca3966e..649440a43fe9 100644 --- a/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html +++ b/corehq/apps/app_manager/templates/app_manager/partials/build_errors.html @@ -191,6 +191,10 @@

{% blocktrans with module_name=error.module.name|trans:langs %} The case list in {{ module_name }} can not use the same "search input instance name" as its Parent Menu. {% endblocktrans %} + {% case "non-unique instance name with parent select module" %} + {% blocktrans with module_name=error.module.name|trans:langs %} + The case list in {{ module_name }} can not use the same "search input instance name" as its Parent Select Menu. + {% endblocktrans %} {% case "inline search to display only forms" %} {% blocktrans with module_name=error.module.name|trans:langs %} {{ module_name }} From cabe6811508e4de60519526e21029ad34397076d Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Mon, 20 Nov 2023 16:22:05 -0800 Subject: [PATCH 05/27] test: update for excluding claim if case already exists in local casedb --- .../tests/data/suite_inline_search/shadow_module_entry.xml | 3 ++- corehq/apps/app_manager/tests/test_advanced_suite.py | 3 ++- corehq/apps/app_manager/tests/test_suite_inline_search.py | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml b/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml index 9993236aa478..05a9bb77df30 100644 --- a/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml +++ b/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml @@ -4,7 +4,8 @@ - + diff --git a/corehq/apps/app_manager/tests/test_advanced_suite.py b/corehq/apps/app_manager/tests/test_advanced_suite.py index 31d8c4d45978..c3deaa528e75 100644 --- a/corehq/apps/app_manager/tests/test_advanced_suite.py +++ b/corehq/apps/app_manager/tests/test_advanced_suite.py @@ -376,7 +376,8 @@ def test_advanced_module_remote_request(self, *args): - + diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index b877c9a8807b..1483c1269c0f 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -91,7 +91,8 @@ def test_inline_search(self):
xmlns1.0
- + @@ -655,7 +656,8 @@ def _expected_entry_query(self, module, custom_instance): - + From 9f70718a492b00264919f4cc79f9f40945205625 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Mon, 20 Nov 2023 16:30:36 -0800 Subject: [PATCH 06/27] test: now supports inline module as target of parent select and inline search using parent select with 'parent' relationship --- .../tests/test_build_errors_inline_search.py | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_build_errors_inline_search.py b/corehq/apps/app_manager/tests/test_build_errors_inline_search.py index 23c53eb356d1..0b214adee2c8 100644 --- a/corehq/apps/app_manager/tests/test_build_errors_inline_search.py +++ b/corehq/apps/app_manager/tests/test_build_errors_inline_search.py @@ -86,44 +86,6 @@ def test_inline_search_previous_screen(self, *args): self.assertIn("workflow previous inline search", _get_error_types(factory.app)) - def test_parent_select_to_inline_search(self, *args): - """an inline module can't be the target of parent select""" - factory = AppFactory(build_version='2.51.0') - m0, _ = factory.new_basic_module('first', 'case') - - m0.search_config = CaseSearch( - search_label=CaseSearchLabel(label={'en': 'Search'}), - properties=[CaseSearchProperty(name=field) for field in ['name', 'greatest_fear']], - auto_launch=True, - inline_search=True, - ) - - m1, _ = factory.new_basic_module('second', 'case') - m1.parent_select.active = True - m1.parent_select.relationship = None - m1.parent_select.module_id = m0.get_or_create_unique_id() - - self.assertIn("parent select is inline search module", _get_error_types(factory.app)) - - def test_parent_select_of_inline_search_module(self, *args): - """inline search can't use parent select with relationship='parent'""" - factory = AppFactory(build_version='2.51.0') - m0, _ = factory.new_basic_module('first', 'case') - - m0.search_config = CaseSearch( - search_label=CaseSearchLabel(label={'en': 'Search'}), - properties=[CaseSearchProperty(name=field) for field in ['name', 'greatest_fear']], - auto_launch=True, - inline_search=True, - ) - - m1, _ = factory.new_basic_module('second', 'case') - - m0.parent_select.active = True - m0.parent_select.module_id = m0.get_or_create_unique_id() - - self.assertIn("inline search parent select relationship", _get_error_types(factory.app)) - def _get_error_types(app): return [error['type'] for error in app.validate_app()] From 2c446d9842a02643ba2bcea77b560e19eea06600 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Mon, 20 Nov 2023 17:29:41 -0800 Subject: [PATCH 07/27] test: claim cases resulting from parent-select's datum --- .../apps/app_manager/tests/test_suite_inline_search.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 0c536aa2243a..b6e46dd9dd0f 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -381,7 +381,10 @@ def test_inline_search_with_parent_select(self):
xmlns1.0
- + + @@ -551,7 +554,10 @@ def test_child_module_with_inline_search_entry(self): - + + From 88800096fd9d4aa3bb5756c5b00f095b109a032f Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Tue, 21 Nov 2023 11:35:30 -0800 Subject: [PATCH 08/27] test: checks suite file for module with inline case search with 'parent' relationship parent select --- .../tests/test_suite_inline_search.py | 70 +++++++++++++++++-- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index b6e46dd9dd0f..378e077bdf57 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -357,13 +357,8 @@ def test_prompt_itemset_mobile_report(self): ) @flag_enabled('USH_SEARCH_FILTER') - def test_inline_search_with_parent_select(self): - """Inline search module can have 'parent select' as long as the - relationship is 'other' (None). - Inline search modules can never be the parent select module. - * post requests aren't included in the entries for the module with parent select - * parent filtering doesn't work since the 'case claim' isn't triggered before filtering - """ + def test_inline_search_with_other_relationship_parent_select_(self): + """Inline search module with 'parent select' relationship is 'other' (None)""" module = self.app.add_module(Module.new_module("Followup2", None)) form = self.app.new_form(2, "Untitled Form", None, attachment=get_simple_form("xmlns1.0")) form.requires = 'case' @@ -423,6 +418,67 @@ def test_inline_search_with_parent_select(self): self.assertXmlPartialEqual(expected_entry, suite, "./entry[1]") + @flag_enabled('USH_SEARCH_FILTER') + def test_inline_search_with_parent_relationship_parent_select(self): + """Inline search module with 'parent select' relationship is 'parent'""" + module = self.app.add_module(Module.new_module("Followup2", None)) + form = self.app.new_form(2, "Untitled Form", None, attachment=get_simple_form("xmlns1.0")) + form.requires = 'case' + module.case_type = 'case' + + self.module.parent_select.active = True + self.module.parent_select.relationship = 'parent' + self.module.parent_select.module_id = module.unique_id + + suite = self.app.create_suite() + + expected_entry = f""" + + +
xmlns1.0
+ + + + + + + + + + + + + + + + + <text> + <locale id="case_search.m0.inputs"/> + </text> + + + + + + + + + + + + +
+
""" # noqa: E501 + + self.assertXmlPartialEqual(expected_entry, suite, "./entry[1]") + @patch_get_xform_resource_overrides() class InlineSearchShadowModuleTest(SimpleTestCase, SuiteMixin): From 13a67c822beeb5bb8fabb68aa76c9ba5bab55b51 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Tue, 21 Nov 2023 17:55:38 -0800 Subject: [PATCH 09/27] test: update tests so parent modules also configured with inline search with a 'parent' parent select relationship --- .../tests/test_suite_inline_search.py | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 378e077bdf57..bcea32cfb4fc 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -579,8 +579,14 @@ def setUp(self): m0, f0 = factory.new_basic_module("case list", "case") factory.form_requires_case(f0) + m0.search_config = CaseSearch( + properties=[CaseSearchProperty(name='name', label={'en': 'Name'})], + auto_launch=True, + inline_search=True, + ) + m1, f1 = factory.new_basic_module("child case list", "case", parent_module=m0) - m1.parent_select = ParentSelect(active=True, relationship=None, module_id=m0.get_or_create_unique_id()) + m1.parent_select = ParentSelect(active=True, relationship='parent', module_id=m0.get_or_create_unique_id()) f2 = factory.new_form(m1) factory.form_requires_case(f1) @@ -596,7 +602,7 @@ def setUp(self): # wrap to have assign_references called self.app = Application.wrap(factory.app.to_json()) - def test_child_module_with_inline_search_entry(self): + def test_child_and_parent_module_with_inline_search_and_parent_relationship_parent_select(self): """An inline search module can be a child module * as long as there is no parent selection or parent_select.relationship = None @@ -612,6 +618,8 @@ def test_child_module_with_inline_search_entry(self): relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_case]) = 0"> + @@ -624,7 +632,22 @@ def test_child_module_with_inline_search_entry(self): - + + <text> + <locale id="case_search.m0.inputs"/> + </text> + + + + + + + + + + + @@ -643,7 +666,7 @@ def test_child_module_with_inline_search_entry(self):
@@ -663,12 +686,12 @@ def test_form_link_in_child_module_with_inline_search(self): - - - + + + From 0278b65a950bec2ce1ab297bb1e68084f4e90bb6 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Tue, 21 Nov 2023 18:07:25 -0800 Subject: [PATCH 10/27] test: update comment + use constant --- .../tests/test_suite_inline_search.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index bcea32cfb4fc..d2c411895b06 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -452,8 +452,8 @@ def test_inline_search_with_parent_relationship_parent_select(self): - + @@ -603,11 +603,8 @@ def setUp(self): self.app = Application.wrap(factory.app.to_json()) def test_child_and_parent_module_with_inline_search_and_parent_relationship_parent_select(self): - """An inline search module can be a child module - * as long as there is no parent selection or parent_select.relationship = None - - An inline search module can never be a parent module - * post requests aren't included in the entries for the child module + """Inline search module as child module with 'parent select''parent' relationship. + Parent module is also inline search. """ suite = self.app.create_suite() @@ -632,7 +629,7 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare <instance id="commcaresession" src="jr://instance/session"/> <instance id="results:inline" src="jr://instance/remote/results:inline"/> <session> - <query default_search="false" dynamic_search="false" storage-instance="results:inline" template="case" url="http://localhost:8000/a/test_domain/phone/search/123/"> + <query default_search="false" dynamic_search="false" storage-instance="{RESULTS_INSTANCE_INLINE}" template="case" url="http://localhost:8000/a/test_domain/phone/search/123/"> <title> <text> <locale id="case_search.m0.inputs"/> @@ -647,7 +644,7 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare </display> </prompt> </query> - <datum id="case_id" nodeset="instance('results:inline')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())]" + <datum id="case_id" nodeset="instance('{RESULTS_INSTANCE_INLINE}')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())]" value="./@case_id" detail-select="m0_case_short"/> <query url="http://localhost:8000/a/test_domain/phone/search/123/" storage-instance="{RESULTS_INSTANCE_INLINE}" template="case" default_search="false" dynamic_search="false"> @@ -666,7 +663,7 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare </prompt> </query> <datum id="case_id_case" - nodeset="instance('results:inline')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())][index/parent=instance('commcaresession')/session/data/case_id]" + nodeset="instance('{RESULTS_INSTANCE_INLINE}')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())][index/parent=instance('commcaresession')/session/data/case_id]" value="./@case_id" detail-select="m1_case_short" detail-confirm="m1_case_long"/> </session> </entry> From e5a2f05d23cb2b7c64802ebc1a446aa97b884e84 Mon Sep 17 00:00:00 2001 From: Jonathan Tang <Jonahtang738@gmail.com> Date: Tue, 21 Nov 2023 18:19:01 -0800 Subject: [PATCH 11/27] test: add custom instance names - required when parent and child both use inline search --- .../tests/test_suite_inline_search.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index d2c411895b06..7de2a3e982e7 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -576,26 +576,29 @@ class InlineSearchChildModuleTest(SimpleTestCase, SuiteMixin): def setUp(self): factory = AppFactory(DOMAIN, "App with inline search and child modules", build_version='2.53.0') - m0, f0 = factory.new_basic_module("case list", "case") + self.m0, f0 = factory.new_basic_module("case list", "case") factory.form_requires_case(f0) - m0.search_config = CaseSearch( + self.m0.search_config = CaseSearch( properties=[CaseSearchProperty(name='name', label={'en': 'Name'})], auto_launch=True, inline_search=True, + instance_name="parent_instance", ) - m1, f1 = factory.new_basic_module("child case list", "case", parent_module=m0) - m1.parent_select = ParentSelect(active=True, relationship='parent', module_id=m0.get_or_create_unique_id()) - f2 = factory.new_form(m1) + self.m1, f1 = factory.new_basic_module("child case list", "case", parent_module=self.m0) + self.m1.parent_select = ParentSelect(active=True, relationship='parent', + module_id=self.m0.get_or_create_unique_id()) + f2 = factory.new_form(self.m1) factory.form_requires_case(f1) factory.form_requires_case(f2) - m1.search_config = CaseSearch( + self.m1.search_config = CaseSearch( properties=[CaseSearchProperty(name='name', label={'en': 'Name'})], auto_launch=True, inline_search=True, + instance_name="child_instance", ) factory.app._id = "123" @@ -627,9 +630,10 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare </command> <instance id="casedb" src="jr://instance/casedb"/> <instance id="commcaresession" src="jr://instance/session"/> - <instance id="results:inline" src="jr://instance/remote/results:inline"/> + <instance id="results:child_instance" src="jr://instance/remote/results:child_instance"/> + <instance id="results:parent_instance" src="jr://instance/remote/results:parent_instance"/> <session> - <query default_search="false" dynamic_search="false" storage-instance="{RESULTS_INSTANCE_INLINE}" template="case" url="http://localhost:8000/a/test_domain/phone/search/123/"> + <query default_search="false" dynamic_search="false" storage-instance="{self.m0.search_config.get_instance_name()}" template="case" url="http://localhost:8000/a/test_domain/phone/search/123/"> <title> <text> <locale id="case_search.m0.inputs"/> @@ -644,10 +648,10 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare </display> </prompt> </query> - <datum id="case_id" nodeset="instance('{RESULTS_INSTANCE_INLINE}')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())]" + <datum id="case_id" nodeset="instance('{self.m0.search_config.get_instance_name()}')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())]" value="./@case_id" detail-select="m0_case_short"/> <query url="http://localhost:8000/a/test_domain/phone/search/123/" - storage-instance="{RESULTS_INSTANCE_INLINE}" template="case" default_search="false" dynamic_search="false"> + storage-instance="{self.m1.search_config.get_instance_name()}" template="case" default_search="false" dynamic_search="false"> <title> <text> <locale id="case_search.m1.inputs"/> @@ -663,7 +667,7 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare </prompt> </query> <datum id="case_id_case" - nodeset="instance('{RESULTS_INSTANCE_INLINE}')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())][index/parent=instance('commcaresession')/session/data/case_id]" + nodeset="instance('{self.m1.search_config.get_instance_name()}')/results/case[@case_type='case'][@status='open'][not(commcare_is_related_case=true())][index/parent=instance('commcaresession')/session/data/case_id]" value="./@case_id" detail-select="m1_case_short" detail-confirm="m1_case_long"/> </session> </entry> @@ -683,12 +687,16 @@ def test_form_link_in_child_module_with_inline_search(self): <partial> <create> <command value="'m0'"/> - <query id="{RESULTS_INSTANCE_INLINE}" value="http://localhost:8000/a/test_domain/phone/case_fixture/123/"> + <query id="{self.m0.search_config.get_instance_name()}" value="http://localhost:8000/a/test_domain/phone/case_fixture/123/"> <data key="case_type" ref="'case'"/> <data key="case_id" ref="instance('commcaresession')/session/data/case_id"/> </query> <datum id="case_id" value="instance('commcaresession')/session/data/case_id"/> <command value="'m1'"/> + <query id="results:child_instance" value="http://localhost:8000/a/test_domain/phone/case_fixture/123/"> + <data key="case_type" ref="'case'"/> + <data key="case_id" ref="instance('commcaresession')/session/data/case_id_case"/> + </query> <datum id="case_id_case" value="instance('commcaresession')/session/data/case_id_case"/> <command value="'m1-f1'"/> </create> From 33a055f523bf8c1a00c914059443fb9ff4c14122 Mon Sep 17 00:00:00 2001 From: Jonathan Tang <Jonahtang738@gmail.com> Date: Tue, 21 Nov 2023 18:55:53 -0800 Subject: [PATCH 12/27] test: update for excluding claim if case already exists in local casedb --- .../app_manager/tests/data/session_endpoint_remote_request.xml | 3 ++- corehq/apps/app_manager/tests/data/suite/remote_request.xml | 3 ++- .../tests/data/suite/remote_request_custom_detail.xml | 3 ++- .../tests/data/suite/search_config_blacklisted_owners.xml | 3 ++- .../tests/data/suite/search_config_default_only.xml | 3 ++- .../app_manager/tests/data/suite/smart_link_remote_request.xml | 3 ++- .../tests/data/suite_registry/shadow_module_remote_request.xml | 3 ++- corehq/apps/app_manager/tests/test_suite_session_endpoints.py | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml b/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml index 3a8862409ff9..baa184f59ff3 100644 --- a/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml +++ b/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml @@ -2,7 +2,8 @@ <remote-request> <post url="https://www.example.com/a/test-domain/phone/claim-case/" relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/{datum_id}]) = 0"> - <data key="case_id" ref="instance('commcaresession')/session/data/{datum_id}"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/{datum_id}]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/{datum_id}"/> </post> <command id="claim_command.{endpoint_id}.{datum_id}"> <display> diff --git a/corehq/apps/app_manager/tests/data/suite/remote_request.xml b/corehq/apps/app_manager/tests/data/suite/remote_request.xml index 0098985d8bc8..2e895cafce04 100644 --- a/corehq/apps/app_manager/tests/data/suite/remote_request.xml +++ b/corehq/apps/app_manager/tests/data/suite/remote_request.xml @@ -2,7 +2,8 @@ <remote-request> <post url="https://www.example.com/a/test_domain/phone/claim-case/" relevant="(count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0) and (instance('groups')/groups/group)"> - <data key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> </post> <command id="search_command.{module_id}"> <display> diff --git a/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml b/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml index a08f777f5e4a..88abe4c63521 100644 --- a/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml +++ b/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml @@ -2,7 +2,8 @@ <remote-request> <post url="https://www.example.com/a/test_domain/phone/claim-case/" relevant="(count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0) and (instance('groups')/groups/group)"> - <data key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> </post> <command id="search_command.m0"> <display> diff --git a/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml b/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml index 0e1c67f761f1..01752b9c21ba 100644 --- a/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml +++ b/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml @@ -2,7 +2,8 @@ <remote-request> <post url="https://www.example.com/a/test_domain/phone/claim-case/" relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0"> - <data key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> </post> <command id="search_command.m0"> <display> diff --git a/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml b/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml index 1023e5e71533..fe509593a824 100644 --- a/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml +++ b/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml @@ -2,7 +2,8 @@ <remote-request> <post url="https://www.example.com/a/test_domain/phone/claim-case/" relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0"> - <data key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> </post> <command id="search_command.m0"> <display> diff --git a/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml b/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml index 97ca48c49a6d..a09a4e333566 100644 --- a/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml +++ b/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml @@ -2,7 +2,8 @@ <remote-request> <post relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0 and instance('results')/results/case[@case_id=instance('commcaresession')/session/data/search_case_id]/commcare_project = instance('commcaresession')/session/user/data/commcare_project" url="https://www.example.com/a/test_domain/phone/claim-case/"> - <data key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> </post> <command id="search_command.m1"> <display> diff --git a/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml b/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml index 51878f0d5977..e544a7cd1aab 100644 --- a/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml +++ b/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml @@ -1,7 +1,8 @@ <partial> <remote-request> <post relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0" url="https://www.example.com/a/test_domain/phone/claim-case/"> - <data key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/search_case_id"/> </post> <command id="search_command.m1"> <display> diff --git a/corehq/apps/app_manager/tests/test_suite_session_endpoints.py b/corehq/apps/app_manager/tests/test_suite_session_endpoints.py index 8caeccf55af4..6feb9afd742c 100644 --- a/corehq/apps/app_manager/tests/test_suite_session_endpoints.py +++ b/corehq/apps/app_manager/tests/test_suite_session_endpoints.py @@ -605,7 +605,8 @@ def test_shadow_module(self): <partial> <remote-request> <post relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id]) = 0" url="http://localhost:8000/a/test-domain/phone/claim-case/"> - <data key="case_id" ref="instance('commcaresession')/session/data/case_id"/> + <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id]) != 0" + key="case_id" ref="instance('commcaresession')/session/data/case_id"/> </post> <command id="claim_command.my_shadow.case_id"> <display> From bcd61d8a80d02d44ab0cb65c8fe881cb646ca65c Mon Sep 17 00:00:00 2001 From: Jonathan Tang <Jonahtang738@gmail.com> Date: Wed, 22 Nov 2023 11:30:21 -0800 Subject: [PATCH 13/27] lint --- .../tests/test_suite_session_endpoints.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_session_endpoints.py b/corehq/apps/app_manager/tests/test_suite_session_endpoints.py index 6feb9afd742c..54ee2fb6a192 100644 --- a/corehq/apps/app_manager/tests/test_suite_session_endpoints.py +++ b/corehq/apps/app_manager/tests/test_suite_session_endpoints.py @@ -58,7 +58,8 @@ def test_multi_case_list_module_session_endpoint_id(self): """ <partial> <endpoint id="case_list"> - <argument id="selected_cases" instance-id="selected_cases" instance-src="jr://instance/selected-entities"/> + <argument id="selected_cases" instance-id="selected_cases" + instance-src="jr://instance/selected-entities"/> <stack> <push> <instance-datum id="selected_cases" value="$selected_cases"/> @@ -519,7 +520,8 @@ def test_inline_case_search_list_module_session_endpoint_id(self): <stack> <push> <command value="'m0'"/> - <query id="results:inline" value="http://localhost:8000/a/test-domain/phone/case_fixture/None/"> + <query id="results:inline" + value="http://localhost:8000/a/test-domain/phone/case_fixture/None/"> <data key="case_type" ref="'mother'"/> <data key="case_id" ref="instance('commcaresession')/session/data/case_id"/> </query> @@ -552,11 +554,13 @@ def test_inline_case_search_multi_list_module_session_endpoint_id(self): """ <partial> <endpoint id="case_list"> - <argument id="selected_cases" instance-id="selected_cases" instance-src="jr://instance/selected-entities"/> + <argument id="selected_cases" instance-id="selected_cases" + instance-src="jr://instance/selected-entities"/> <stack> <push> <command value="'m0'"/> - <query id="results:inline" value="http://localhost:8000/a/test-domain/phone/case_fixture/None/"> + <query id="results:inline" + value="http://localhost:8000/a/test-domain/phone/case_fixture/None/"> <data key="case_type" ref="'mother'"/> <data key="case_id" nodeset="instance('selected_cases')/results/value" ref="."/> </query> @@ -604,7 +608,8 @@ def test_shadow_module(self): """ <partial> <remote-request> - <post relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id]) = 0" url="http://localhost:8000/a/test-domain/phone/claim-case/"> + <post relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id]) = 0" + url="http://localhost:8000/a/test-domain/phone/claim-case/"> <data exclude="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id]) != 0" key="case_id" ref="instance('commcaresession')/session/data/case_id"/> </post> From cbc5d4c5b75f077f069ea787837b081c68a537a6 Mon Sep 17 00:00:00 2001 From: Jonathan Tang <Jonahtang738@gmail.com> Date: Tue, 5 Dec 2023 15:25:23 -0800 Subject: [PATCH 14/27] feat+test: filter for only cases that are children of "parent select" target module's case type otherwise the results that are returned may not be child cases of the parent case. --- .../suite_xml/post_process/remote_requests.py | 13 +++++++++++++ .../app_manager/tests/test_suite_inline_search.py | 5 +++-- corehq/apps/app_manager/util.py | 9 +++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py index d2bd39a1e897..3ee1fd899fd5 100644 --- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py +++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py @@ -64,6 +64,7 @@ module_offers_registry_search, module_uses_inline_search, module_uses_include_all_related_cases, + module_uses_inline_search_with_parent_relationship_parent_select, ) from corehq.apps.app_manager.xpath import ( CaseClaimXpath, @@ -82,6 +83,7 @@ CASE_SEARCH_REGISTRY_ID_KEY, CASE_SEARCH_INCLUDE_ALL_RELATED_CASES_KEY, CASE_SEARCH_SORT_KEY, + CASE_SEARCH_XPATH_QUERY_KEY, ) from corehq.util.timer import time_method from corehq.util.view_utils import absolute_reverse @@ -297,6 +299,17 @@ def _remote_request_query_datums(self): ref=f"'{','.join(refs)}'", ) ) + if module_uses_inline_search_with_parent_relationship_parent_select(self.module): + parent_module_id = self.module.parent_select.module_id + parent_module = self.app.get_module_by_unique_id(parent_module_id) + parent_case_type = parent_module.case_type + datums.append( + QueryData( + key=CASE_SEARCH_XPATH_QUERY_KEY, + ref=f"ancestor-exists(parent, @case_type={parent_case_type})" + ) + ) + return datums def build_query_prompts(self): diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 7de2a3e982e7..23ce6b2faffc 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -424,7 +424,7 @@ def test_inline_search_with_parent_relationship_parent_select(self): module = self.app.add_module(Module.new_module("Followup2", None)) form = self.app.new_form(2, "Untitled Form", None, attachment=get_simple_form("xmlns1.0")) form.requires = 'case' - module.case_type = 'case' + module.case_type = 'parent_case' self.module.parent_select.active = True self.module.parent_select.relationship = 'parent' @@ -452,7 +452,7 @@ def test_inline_search_with_parent_relationship_parent_select(self): <instance id="commcaresession" src="jr://instance/session"/> <instance id="results:inline" src="jr://instance/remote/results:inline"/> <session> - <datum id="parent_id" nodeset="instance('casedb')/casedb/case[@case_type='case'][@status='open']" + <datum id="parent_id" nodeset="instance('casedb')/casedb/case[@case_type='parent_case'][@status='open']" value="./@case_id" detail-select="m2_case_short"/> <query url="http://localhost:8000/a/test_domain/phone/search/123/" storage-instance="{RESULTS_INSTANCE_INLINE}" template="case" default_search="false" dynamic_search="false"> @@ -462,6 +462,7 @@ def test_inline_search_with_parent_relationship_parent_select(self): </text> + diff --git a/corehq/apps/app_manager/util.py b/corehq/apps/app_manager/util.py index a7527996d486..8c088fe12bb8 100644 --- a/corehq/apps/app_manager/util.py +++ b/corehq/apps/app_manager/util.py @@ -197,6 +197,7 @@ def change_xmlns(xform, old_xmlns, new_xmlns): return xml + CASE_TYPE_REGEX = r'^[\w-]+$' _case_type_regex = re.compile(CASE_TYPE_REGEX) @@ -423,6 +424,14 @@ def module_uses_inline_search(module): ) +def module_uses_inline_search_with_parent_relationship_parent_select(module): + return ( + module_uses_inline_search(module) + and module.parent_select.active + and module.parent_select.relationship == 'parent' + ) + + def module_uses_include_all_related_cases(module): return ( module_offers_search(module) From bafd2e0fe9819444c1c2d25a930767098d6ffddb Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Tue, 5 Dec 2023 15:33:19 -0800 Subject: [PATCH 15/27] test: filters for child cases that have parents that are the target "parent-select"'s case type the test differentiates the case type between the child and parent to check that the correct case type is uesd for the ref --- .../tests/test_suite_inline_search.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 23ce6b2faffc..65ed39bfd602 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -587,7 +587,7 @@ def setUp(self): instance_name="parent_instance", ) - self.m1, f1 = factory.new_basic_module("child case list", "case", parent_module=self.m0) + self.m1, f1 = factory.new_basic_module("child case list", "child_case", parent_module=self.m0) self.m1.parent_select = ParentSelect(active=True, relationship='parent', module_id=self.m0.get_or_create_unique_id()) f2 = factory.new_form(self.m1) @@ -616,9 +616,9 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare - + relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_child_case]) = 0"> + - + + @@ -667,8 +668,8 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare -
@@ -695,10 +696,10 @@ def test_form_link_in_child_module_with_inline_search(self): - - + + - + """ # noqa: E501 From 05683aecda28234bd997f8682bfd1ebdd660e1c2 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Wed, 6 Dec 2023 10:37:49 -0800 Subject: [PATCH 16/27] bug: gets the final case datums after processing. get_datum_meta_module contains unprocessed datums which ids are changed later in the entry creation --- corehq/apps/app_manager/suite_xml/sections/entries.py | 2 +- corehq/apps/app_manager/tests/test_suite_inline_search.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index e9831070a6d3..8e4bda4fa90e 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -257,7 +257,7 @@ def add_post_to_entry(self, form, module, e): None, module, [], case_session_var=case_session_var, storage_instance=storage_instance, exclude_relevant=case_search_sync_cases_on_form_entry_enabled_for_domain(self.app.domain)) e.post = remote_request_factory.build_remote_request_post() - datum_ids = [form_datum.datum.id for form_datum in self.get_datum_meta_module(module, use_filter=True) + datum_ids = [form_datum.datum.id for form_datum in self.get_case_datums_basic_module(module, form) if form_datum.datum.id != case_session_var] if hasattr(module, 'parent_select') and module.parent_select.active: for datum_id in datum_ids: diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 65ed39bfd602..12c2d5414cc6 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -619,8 +619,6 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id_child_case]) = 0"> - From 3baa94cde94c9b2f5ff5545bb063fa5f5f54ab08 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Wed, 6 Dec 2023 10:51:55 -0800 Subject: [PATCH 17/27] refactor: gets case_datum_id only if it's needed --- corehq/apps/app_manager/suite_xml/sections/entries.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index 8e4bda4fa90e..4757d00e74e8 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -257,12 +257,12 @@ def add_post_to_entry(self, form, module, e): None, module, [], case_session_var=case_session_var, storage_instance=storage_instance, exclude_relevant=case_search_sync_cases_on_form_entry_enabled_for_domain(self.app.domain)) e.post = remote_request_factory.build_remote_request_post() - datum_ids = [form_datum.datum.id for form_datum in self.get_case_datums_basic_module(module, form) - if form_datum.datum.id != case_session_var] if hasattr(module, 'parent_select') and module.parent_select.active: - for datum_id in datum_ids: + case_datum_ids = [form_datum.datum.id for form_datum in self.get_case_datums_basic_module(module, form) + if form_datum.datum.id != case_session_var] + for case_datum_id in case_datum_ids: data = QueryData(key='case_id') - data.ref = QuerySessionXPath(datum_id).instance() + data.ref = QuerySessionXPath(case_datum_id).instance() data.exclude = CaseIDXPath(data.ref).case().count().neq(0) e.post.data.append(data) From 3f45791c48888f92e16f576ae92d107005b57ca2 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Wed, 6 Dec 2023 11:02:22 -0800 Subject: [PATCH 18/27] feat: further restrict conditions for adding all case datums blocks to post block --- corehq/apps/app_manager/suite_xml/sections/entries.py | 3 ++- .../apps/app_manager/tests/test_suite_inline_search.py | 2 -- corehq/apps/app_manager/util.py | 9 ++++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index 4757d00e74e8..7c7016155705 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -38,6 +38,7 @@ module_loads_registry_case, module_offers_search, module_uses_inline_search, + module_uses_inline_search_with_parent_relationship_parent_select, ) from corehq.apps.app_manager.xform import ( autoset_owner_id_for_advanced_action, @@ -257,7 +258,7 @@ def add_post_to_entry(self, form, module, e): None, module, [], case_session_var=case_session_var, storage_instance=storage_instance, exclude_relevant=case_search_sync_cases_on_form_entry_enabled_for_domain(self.app.domain)) e.post = remote_request_factory.build_remote_request_post() - if hasattr(module, 'parent_select') and module.parent_select.active: + if module_uses_inline_search_with_parent_relationship_parent_select(module): case_datum_ids = [form_datum.datum.id for form_datum in self.get_case_datums_basic_module(module, form) if form_datum.datum.id != case_session_var] for case_datum_id in case_datum_ids: diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 12c2d5414cc6..22b4acbc7e53 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -378,8 +378,6 @@ def test_inline_search_with_other_relationship_parent_select_(self): relevant="count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/case_id]) = 0"> - diff --git a/corehq/apps/app_manager/util.py b/corehq/apps/app_manager/util.py index 8c088fe12bb8..5d3c7e63daab 100644 --- a/corehq/apps/app_manager/util.py +++ b/corehq/apps/app_manager/util.py @@ -408,9 +408,9 @@ def module_offers_search(module): return ( isinstance(module, (Module, AdvancedModule, ShadowModule)) and - module.search_config and - (module.search_config.properties or - module.search_config.default_properties) + module.search_config + and (module.search_config.properties + or module.search_config.default_properties) ) @@ -427,6 +427,7 @@ def module_uses_inline_search(module): def module_uses_inline_search_with_parent_relationship_parent_select(module): return ( module_uses_inline_search(module) + and hasattr(module, 'parent_select') and module.parent_select.active and module.parent_select.relationship == 'parent' ) @@ -531,6 +532,8 @@ def _app_callout_templates(): data = [] while True: yield data + + app_callout_templates = _app_callout_templates() From ea5b9f31cbaa103c4bbb5dc74755eb6b45367bbf Mon Sep 17 00:00:00 2001 From: Jonathan Tang <88759246+Jtang-1@users.noreply.github.com> Date: Wed, 6 Dec 2023 11:46:27 -0800 Subject: [PATCH 19/27] bug: case search query string requires quote Co-authored-by: Simon Kelly --- .../apps/app_manager/suite_xml/post_process/remote_requests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py index 3ee1fd899fd5..a8e966c8d9e5 100644 --- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py +++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py @@ -306,7 +306,7 @@ def _remote_request_query_datums(self): datums.append( QueryData( key=CASE_SEARCH_XPATH_QUERY_KEY, - ref=f"ancestor-exists(parent, @case_type={parent_case_type})" + ref=f"ancestor-exists(parent, @case_type='{parent_case_type}')" ) ) From 076d28b5d9a56bf11fb2639338e92955288f2fb6 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Wed, 6 Dec 2023 12:05:41 -0800 Subject: [PATCH 20/27] test: corrects case search query string --- corehq/apps/app_manager/tests/test_suite_inline_search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 22b4acbc7e53..0f28c7da6c9f 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -460,7 +460,7 @@ def test_inline_search_with_parent_relationship_parent_select(self): - + @@ -655,7 +655,7 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare - + From f8b91a76d9b24e2f1bf414cba22b329dc9761139 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Fri, 8 Dec 2023 11:54:55 -0800 Subject: [PATCH 21/27] bug: ref string requires to be enclosed by quotes --- .../apps/app_manager/suite_xml/post_process/remote_requests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py index a8e966c8d9e5..2d898fec6155 100644 --- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py +++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py @@ -306,7 +306,7 @@ def _remote_request_query_datums(self): datums.append( QueryData( key=CASE_SEARCH_XPATH_QUERY_KEY, - ref=f"ancestor-exists(parent, @case_type='{parent_case_type}')" + ref=f"\"ancestor-exists(parent, @case_type='{parent_case_type}')\"" ) ) From 93a09b7bca6e327f303bfd9c3dfdd4412e033727 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Fri, 8 Dec 2023 16:38:33 -0800 Subject: [PATCH 22/27] makes multi_select_relevant into class method --- corehq/apps/app_manager/xpath.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/xpath.py b/corehq/apps/app_manager/xpath.py index 06c900e4cc10..4ee3a8198e91 100644 --- a/corehq/apps/app_manager/xpath.py +++ b/corehq/apps/app_manager/xpath.py @@ -352,7 +352,8 @@ def default_relevant(self): # count(instance('casedb')/casedb/case[@case_id=instance('commcaresession')/session/data/search_case_id]) = 0 return CaseIDXPath(session_var(self.session_var_name)).case().count().eq(0) - def multi_select_relevant(self): + @classmethod + def multi_select_relevant(cls): # Verifies that there's at least one case that isn't yet owned by the user return XPath("$case_id").neq(XPath.string("")) From 2f491dfc148a46a9322c99cc9d5686fd2c72c831 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Fri, 8 Dec 2023 16:41:30 -0800 Subject: [PATCH 23/27] test: corrects case search query to be enclosed in quotes --- corehq/apps/app_manager/tests/test_suite_inline_search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 0f28c7da6c9f..7aa0e79c65ef 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -460,7 +460,7 @@ def test_inline_search_with_parent_relationship_parent_select(self): - + @@ -655,7 +655,7 @@ def test_child_and_parent_module_with_inline_search_and_parent_relationship_pare - + From 20703862f6ddbf67bb874fb4980e6a32f72c2bc1 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Fri, 8 Dec 2023 16:43:48 -0800 Subject: [PATCH 24/27] relevant check needs to account for all data elements within post. --- corehq/apps/app_manager/suite_xml/sections/entries.py | 2 ++ corehq/apps/app_manager/tests/test_suite_inline_search.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index 7c7016155705..2b2a42860ff2 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -46,6 +46,7 @@ autoset_owner_id_for_subcase, ) from corehq.apps.app_manager.xpath import ( + CaseClaimXpath, CaseIDXPath, ItemListFixtureXpath, ProductInstanceXpath, @@ -266,6 +267,7 @@ def add_post_to_entry(self, form, module, e): data.ref = QuerySessionXPath(case_datum_id).instance() data.exclude = CaseIDXPath(data.ref).case().count().neq(0) e.post.data.append(data) + e.post.relevant = CaseClaimXpath.multi_select_relevant() def entry_for_module(self, module): # avoid circular dependency diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 7aa0e79c65ef..7119c2881c9e 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -435,7 +435,7 @@ def test_inline_search_with_parent_relationship_parent_select(self):
xmlns1.0
+ relevant="$case_id != ''"> + relevant="$case_id != ''"> Date: Mon, 11 Dec 2023 10:21:04 -0800 Subject: [PATCH 25/27] bug: datums for new cases should not in post.data as we do not need to claim these new cases --- corehq/apps/app_manager/suite_xml/sections/entries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index 2b2a42860ff2..c0eb258c2c09 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -261,7 +261,7 @@ def add_post_to_entry(self, form, module, e): e.post = remote_request_factory.build_remote_request_post() if module_uses_inline_search_with_parent_relationship_parent_select(module): case_datum_ids = [form_datum.datum.id for form_datum in self.get_case_datums_basic_module(module, form) - if form_datum.datum.id != case_session_var] + if (form_datum.datum.id != case_session_var and not form_datum.is_new_case_id)] for case_datum_id in case_datum_ids: data = QueryData(key='case_id') data.ref = QuerySessionXPath(case_datum_id).instance() From 4d44e5b64ddf0143ce86442ee29cff6217bf9d87 Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Mon, 11 Dec 2023 11:24:02 -0800 Subject: [PATCH 26/27] only have "exclude" attribute to data element if only claiming a single case there is already a "relevant" attribute on the "post" element that does the check when we're claimining a single case. Having the "exclude" on the data element with the same xpath expression means we end up checking twice for the same case. --- .../suite_xml/post_process/remote_requests.py | 3 ++- .../tests/data/session_endpoint_remote_request.xml | 3 +-- .../apps/app_manager/tests/data/suite/remote_request.xml | 3 +-- .../tests/data/suite/remote_request_custom_detail.xml | 3 +-- .../data/suite/search_config_blacklisted_owners.xml | 3 +-- .../tests/data/suite/search_config_default_only.xml | 3 +-- .../tests/data/suite/smart_link_remote_request.xml | 3 +-- .../data/suite_inline_search/shadow_module_entry.xml | 3 +-- .../data/suite_registry/shadow_module_remote_request.xml | 3 +-- corehq/apps/app_manager/tests/test_advanced_suite.py | 3 +-- .../apps/app_manager/tests/test_suite_inline_search.py | 9 +++------ .../app_manager/tests/test_suite_session_endpoints.py | 3 +-- 12 files changed, 15 insertions(+), 27 deletions(-) diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py index 2d898fec6155..2a44df8f38d2 100644 --- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py +++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py @@ -155,7 +155,8 @@ def build_case_id_query_data(self): data.exclude = self._get_multi_select_exclude() else: data.ref = QuerySessionXPath(self.case_session_var).instance() - if not self.exclude_relevant: + if (not self.exclude_relevant + and module_uses_inline_search_with_parent_relationship_parent_select(self.module)): data.exclude = CaseIDXPath(data.ref).case().count().neq(0) return data diff --git a/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml b/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml index baa184f59ff3..3a8862409ff9 100644 --- a/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml +++ b/corehq/apps/app_manager/tests/data/session_endpoint_remote_request.xml @@ -2,8 +2,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite/remote_request.xml b/corehq/apps/app_manager/tests/data/suite/remote_request.xml index 2e895cafce04..0098985d8bc8 100644 --- a/corehq/apps/app_manager/tests/data/suite/remote_request.xml +++ b/corehq/apps/app_manager/tests/data/suite/remote_request.xml @@ -2,8 +2,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml b/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml index 88abe4c63521..a08f777f5e4a 100644 --- a/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml +++ b/corehq/apps/app_manager/tests/data/suite/remote_request_custom_detail.xml @@ -2,8 +2,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml b/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml index 01752b9c21ba..0e1c67f761f1 100644 --- a/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml +++ b/corehq/apps/app_manager/tests/data/suite/search_config_blacklisted_owners.xml @@ -2,8 +2,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml b/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml index fe509593a824..1023e5e71533 100644 --- a/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml +++ b/corehq/apps/app_manager/tests/data/suite/search_config_default_only.xml @@ -2,8 +2,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml b/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml index a09a4e333566..97ca48c49a6d 100644 --- a/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml +++ b/corehq/apps/app_manager/tests/data/suite/smart_link_remote_request.xml @@ -2,8 +2,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml b/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml index 5d3321b0f845..cc51281d29f4 100644 --- a/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml +++ b/corehq/apps/app_manager/tests/data/suite_inline_search/shadow_module_entry.xml @@ -4,8 +4,7 @@ - + diff --git a/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml b/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml index e544a7cd1aab..51878f0d5977 100644 --- a/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml +++ b/corehq/apps/app_manager/tests/data/suite_registry/shadow_module_remote_request.xml @@ -1,8 +1,7 @@ - + diff --git a/corehq/apps/app_manager/tests/test_advanced_suite.py b/corehq/apps/app_manager/tests/test_advanced_suite.py index 5779614472e4..b447b94cb9fa 100644 --- a/corehq/apps/app_manager/tests/test_advanced_suite.py +++ b/corehq/apps/app_manager/tests/test_advanced_suite.py @@ -382,8 +382,7 @@ def test_advanced_module_remote_request(self, *args): - + diff --git a/corehq/apps/app_manager/tests/test_suite_inline_search.py b/corehq/apps/app_manager/tests/test_suite_inline_search.py index 7119c2881c9e..98b11880af40 100644 --- a/corehq/apps/app_manager/tests/test_suite_inline_search.py +++ b/corehq/apps/app_manager/tests/test_suite_inline_search.py @@ -91,8 +91,7 @@ def test_inline_search(self):
xmlns1.0
- + @@ -376,8 +375,7 @@ def test_inline_search_with_other_relationship_parent_select_(self):
xmlns1.0
- + @@ -744,8 +742,7 @@ def _expected_entry_query(self, module, custom_instance): - + diff --git a/corehq/apps/app_manager/tests/test_suite_session_endpoints.py b/corehq/apps/app_manager/tests/test_suite_session_endpoints.py index 54ee2fb6a192..20befecb3076 100644 --- a/corehq/apps/app_manager/tests/test_suite_session_endpoints.py +++ b/corehq/apps/app_manager/tests/test_suite_session_endpoints.py @@ -610,8 +610,7 @@ def test_shadow_module(self): - + From ba1526721640941be0ea8ad5d29ebb47ebf3a83e Mon Sep 17 00:00:00 2001 From: Jonathan Tang Date: Mon, 11 Dec 2023 23:15:23 -0800 Subject: [PATCH 27/27] rename variable for clarity --- corehq/apps/app_manager/models.py | 2 +- .../apps/app_manager/suite_xml/post_process/remote_requests.py | 2 +- corehq/apps/app_manager/suite_xml/sections/entries.py | 2 +- corehq/apps/app_manager/xpath.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/corehq/apps/app_manager/models.py b/corehq/apps/app_manager/models.py index a12f7b980d0d..7e243acc84fe 100644 --- a/corehq/apps/app_manager/models.py +++ b/corehq/apps/app_manager/models.py @@ -2188,7 +2188,7 @@ def get_instance_name(self): def get_relevant(self, case_session_var, multi_select=False): xpath = CaseClaimXpath(case_session_var) - default_condition = xpath.multi_select_relevant() if multi_select else xpath.default_relevant() + default_condition = xpath.multi_case_relevant() if multi_select else xpath.default_relevant() if self.additional_relevant: return f"({default_condition}) and ({self.additional_relevant})" return default_condition diff --git a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py index 2a44df8f38d2..90789a77aea4 100644 --- a/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py +++ b/corehq/apps/app_manager/suite_xml/post_process/remote_requests.py @@ -456,7 +456,7 @@ def __init__(self, suite, module, detail_section_elements, endpoint_id, case_ses def get_post_relevant(self): xpath = CaseClaimXpath(self.case_session_var) if self.module.is_multi_select(): - return xpath.multi_select_relevant() + return xpath.multi_case_relevant() return xpath.default_relevant() def build_command(self): diff --git a/corehq/apps/app_manager/suite_xml/sections/entries.py b/corehq/apps/app_manager/suite_xml/sections/entries.py index c0eb258c2c09..2822426f5f17 100644 --- a/corehq/apps/app_manager/suite_xml/sections/entries.py +++ b/corehq/apps/app_manager/suite_xml/sections/entries.py @@ -267,7 +267,7 @@ def add_post_to_entry(self, form, module, e): data.ref = QuerySessionXPath(case_datum_id).instance() data.exclude = CaseIDXPath(data.ref).case().count().neq(0) e.post.data.append(data) - e.post.relevant = CaseClaimXpath.multi_select_relevant() + e.post.relevant = CaseClaimXpath.multi_case_relevant() def entry_for_module(self, module): # avoid circular dependency diff --git a/corehq/apps/app_manager/xpath.py b/corehq/apps/app_manager/xpath.py index 4ee3a8198e91..d9b2ec677017 100644 --- a/corehq/apps/app_manager/xpath.py +++ b/corehq/apps/app_manager/xpath.py @@ -353,7 +353,7 @@ def default_relevant(self): return CaseIDXPath(session_var(self.session_var_name)).case().count().eq(0) @classmethod - def multi_select_relevant(cls): + def multi_case_relevant(cls): # Verifies that there's at least one case that isn't yet owned by the user return XPath("$case_id").neq(XPath.string(""))