diff --git a/commcare_connect/opportunity/app_xml.py b/commcare_connect/opportunity/app_xml.py index da2a525e..87e3e8c2 100644 --- a/commcare_connect/opportunity/app_xml.py +++ b/commcare_connect/opportunity/app_xml.py @@ -22,6 +22,12 @@ class Module: time_estimate: int +@dataclass +class DeliverUnit: + id: str + name: str + + class AppNoBuildException(CommCareHQAPIException): pass @@ -31,6 +37,11 @@ def get_connect_blocks_for_app(domain: str, app_id: str) -> list[Module]: return list(itertools.chain.from_iterable(extract_connect_blocks(form_xml) for form_xml in form_xmls)) +def get_deliver_units_for_app(domain: str, app_id: str) -> list[DeliverUnit]: + form_xmls = get_form_xml_for_app(domain, app_id) + return list(itertools.chain.from_iterable(extract_deliver_units(form_xml) for form_xml in form_xmls)) + + def get_form_xml_for_app(domain: str, app_id: str) -> list[str]: """Download the CCZ for the given app and return the XML for each form.""" @@ -74,6 +85,18 @@ def extract_modules(xml: ET.Element): yield Module(slug, name, description, int(time_estimate) if time_estimate is not None else None) +def extract_deliver_units(form_xml): + xml = ET.fromstring(form_xml) + yield from extract_deliver_unit(xml) + + +def extract_deliver_unit(xml: ET.Element): + for block in xml.findall(f".//{XMLNS_PREFIX}deliver"): + slug = block.get("id") + name = get_element_text(block, "name") + yield DeliverUnit(slug, name) + + def get_element_text(parent, name) -> str | None: element = parent.find(f"{XMLNS_PREFIX}{name}") return element.text if element is not None else None diff --git a/commcare_connect/opportunity/tasks.py b/commcare_connect/opportunity/tasks.py index 0bbd9dc1..e09523dc 100644 --- a/commcare_connect/opportunity/tasks.py +++ b/commcare_connect/opportunity/tasks.py @@ -4,22 +4,30 @@ from django.core.files.storage import default_storage from django.utils.timezone import now -from commcare_connect.opportunity.app_xml import get_connect_blocks_for_app +from commcare_connect.opportunity.app_xml import get_connect_blocks_for_app, get_deliver_units_for_app from commcare_connect.opportunity.export import export_empty_payment_table, export_user_visit_data from commcare_connect.opportunity.forms import DateRanges -from commcare_connect.opportunity.models import LearnModule, Opportunity, OpportunityAccess, VisitValidationStatus +from commcare_connect.opportunity.models import ( + DeliverUnit, + LearnModule, + Opportunity, + OpportunityAccess, + VisitValidationStatus, +) from commcare_connect.users.helpers import invite_user from commcare_connect.users.models import User from config import celery_app @celery_app.task() -def create_learn_modules_assessments(opportunity_id): +def create_learn_modules_and_deliver_units(opportunity_id): opportunity = Opportunity.objects.filter(id=opportunity_id).first() learn_app = opportunity.learn_app - connect_blocks = get_connect_blocks_for_app(learn_app.cc_domain, learn_app.cc_app_id) + deliver_app = opportunity.deliver_app + learn_app_connect_blocks = get_connect_blocks_for_app(learn_app.cc_domain, learn_app.cc_app_id) + deliver_app_connect_blocks = get_deliver_units_for_app(deliver_app.cc_domain, deliver_app.cc_app_id) - for block in connect_blocks: + for block in learn_app_connect_blocks: LearnModule.objects.update_or_create( app=learn_app, slug=block.id, @@ -30,6 +38,9 @@ def create_learn_modules_assessments(opportunity_id): }, ) + for block in deliver_app_connect_blocks: + DeliverUnit.objects.get_or_create(app=deliver_app, slug=block.id, defaults=dict(name=block.name)) + @celery_app.task() def add_connect_users(user_list: list[str], opportunity_id: str): diff --git a/commcare_connect/opportunity/views.py b/commcare_connect/opportunity/views.py index a6ff21e1..66c1793a 100644 --- a/commcare_connect/opportunity/views.py +++ b/commcare_connect/opportunity/views.py @@ -33,7 +33,7 @@ from commcare_connect.opportunity.tables import OpportunityAccessTable, PaymentTable, UserStatusTable, UserVisitTable from commcare_connect.opportunity.tasks import ( add_connect_users, - create_learn_modules_assessments, + create_learn_modules_and_deliver_units, generate_payment_export, generate_visit_export, ) @@ -75,7 +75,7 @@ def get_form_kwargs(self): def form_valid(self, form: OpportunityCreationForm) -> HttpResponse: response = super().form_valid(form) - create_learn_modules_assessments.delay(self.object.id) + create_learn_modules_and_deliver_units.delay(self.object.id) return response diff --git a/commcare_connect/templates/opportunity/opportunity_detail.html b/commcare_connect/templates/opportunity/opportunity_detail.html index d3f76c6f..3cd705a5 100644 --- a/commcare_connect/templates/opportunity/opportunity_detail.html +++ b/commcare_connect/templates/opportunity/opportunity_detail.html @@ -114,27 +114,64 @@

{{ object.name }}

-

Learn App Modules

- - - - - - - - - - - {% for module in object.learn_app.learn_modules.all %} - - - - - - {% endfor %} - -
NameDescriptionTime Estimate
{{ module.name }}{{ module.description }}{{ module.time_estimate }} hour{{ module.time_estimate|pluralize:",s" }}
-
+
+
+

+ +

+
+
+ + + + + + + + + + {% for module in object.learn_app.learn_modules.all %} + + + + + + {% endfor %} + +
NameDescriptionTime Estimate
{{ module.name }}{{ module.description }}{{ module.time_estimate }} hour{{ module.time_estimate|pluralize:",s" }}
+
+
+
+
+

+ +

+
+
+ + + + + + + + + {% for unit in object.deliver_app.deliver_units.all %} + + + + + {% endfor %} + +
NameID
{{ unit.name }}{{ unit.slug }}
+
+
+
+