Skip to content

Commit 619f6a8

Browse files
Merge pull request #15 from OpenSPP/fix/spp-programs-wizard-modal-close
fix(spp_programs,spp_change_request_v2): reliably close wizard modals and hide Geographic Targeting
2 parents d9d9b66 + 6fe3cc1 commit 619f6a8

11 files changed

Lines changed: 121 additions & 85 deletions

spp_change_request_v2/static/src/js/create_change_request.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,39 @@ import {FormController} from "@web/views/form/form_controller";
44
import {ListController} from "@web/views/list/list_controller";
55
import {onWillStart} from "@odoo/owl";
66
import {patch} from "@web/core/utils/patch";
7+
import {registry} from "@web/core/registry";
78
import {useService} from "@web/core/utils/hooks";
89
import {user} from "@web/core/user";
910

11+
/**
12+
* Client action to close wizard modal and then open CR detail form.
13+
* Uses async/await to ensure the modal is fully closed before navigating.
14+
*/
15+
async function openCRCloseModal(env, action) {
16+
const actionService = env.services.action;
17+
const params = action.params || {};
18+
19+
await actionService.doAction(
20+
{type: "ir.actions.act_window_close"},
21+
{clearBreadcrumbs: true}
22+
);
23+
24+
if (params.res_id) {
25+
await actionService.doAction({
26+
type: "ir.actions.act_window",
27+
name: params.name || "Change Request Details",
28+
res_model: params.res_model,
29+
res_id: params.res_id,
30+
view_mode: "form",
31+
views: [[params.view_id || false, "form"]],
32+
target: "current",
33+
context: params.context || {},
34+
});
35+
}
36+
}
37+
38+
registry.category("actions").add("open_cr_close_modal", openCRCloseModal);
39+
1040
patch(ListController.prototype, {
1141
setup() {
1242
super.setup();

spp_change_request_v2/wizards/create_wizard.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -232,35 +232,38 @@ def action_create_draft(self):
232232
}
233233
)
234234

235-
# Open the detail form directly for editing
235+
# Close wizard modal and open detail form using client action
236+
# The client action ensures the modal is fully closed before navigating
236237
detail = cr.get_detail()
237238
if detail:
238239
view_id = self.request_type_id.get_detail_form_view_id()
239240
return {
240-
"type": "ir.actions.act_window",
241-
"name": "Change Request Details",
242-
"res_model": cr.detail_res_model,
243-
"res_id": detail.id,
244-
"view_mode": "form",
245-
"view_id": view_id,
246-
"target": "current",
247-
"context": {
248-
"create": False,
249-
"delete": False,
250-
"form_view_initial_mode": "edit",
241+
"type": "ir.actions.client",
242+
"tag": "open_cr_close_modal",
243+
"params": {
244+
"name": _("Change Request Details"),
245+
"res_model": cr.detail_res_model,
246+
"res_id": detail.id,
247+
"view_id": view_id,
248+
"context": {
249+
"create": False,
250+
"delete": False,
251+
"form_view_initial_mode": "edit",
252+
},
251253
},
252254
}
253255

254256
# Fallback: open CR form if no detail model configured
255257
return {
256-
"type": "ir.actions.act_window",
257-
"name": "Change Request",
258-
"res_model": "spp.change.request",
259-
"res_id": cr.id,
260-
"view_mode": "form",
261-
"target": "current",
262-
"context": {
263-
"form_view_initial_mode": "edit",
258+
"type": "ir.actions.client",
259+
"tag": "open_cr_close_modal",
260+
"params": {
261+
"name": _("Change Request"),
262+
"res_model": "spp.change.request",
263+
"res_id": cr.id,
264+
"context": {
265+
"form_view_initial_mode": "edit",
266+
},
264267
},
265268
}
266269

spp_programs/static/src/js/create_program.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {useService} from "@web/core/utils/hooks";
1515
async function openProgramCloseModal(env, action) {
1616
const actionService = env.services.action;
1717
const programId = action.params?.program_id;
18+
const programName = action.params?.name || "Program";
19+
const viewId = action.params?.view_id || false;
1820

1921
await actionService.doAction(
2022
{type: "ir.actions.act_window_close"},
@@ -24,10 +26,10 @@ async function openProgramCloseModal(env, action) {
2426
if (programId) {
2527
await actionService.doAction({
2628
type: "ir.actions.act_window",
27-
name: "Program",
29+
name: programName,
2830
res_model: "spp.program",
2931
res_id: programId,
30-
views: [[false, "form"]],
32+
views: [[viewId, "form"]],
3133
target: "current",
3234
});
3335
}

spp_programs/tests/test_create_program_wiz.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def setUp(self):
3434
}
3535
)
3636

37-
self.program = self._program_create_wiz.create_program()
37+
self._program_action = self._program_create_wiz.create_program()
3838
# self.cycle_manager_default = (
3939
# self._program_create_wiz.create_cycle_manager_default(self.program.id)
4040
# )
@@ -69,19 +69,19 @@ def test_02_create_program(self):
6969
)
7070
res = new_wiz.create_program()
7171
self.assertEqual(type(res), dict, "Action should be in json format!")
72-
for key in ("type", "res_model", "res_id"):
72+
for key in ("type", "tag", "params"):
7373
self.assertIn(key, res.keys(), f"Key `{key}` is missing!")
7474
self.assertEqual(
7575
res["type"],
76-
"ir.actions.act_window",
76+
"ir.actions.client",
7777
"Action for program should be returned!",
7878
)
79-
self.assertEqual(res["res_model"], "spp.program", "Action for program should be return!")
80-
self.assertTrue(res["res_id"], "New record for program should be existed!")
79+
self.assertEqual(res["tag"], "open_program_close_modal", "Client action tag should match!")
80+
self.assertTrue(res["params"]["program_id"], "New record for program should be existed!")
8181

8282
def test_03_get_eligibility_manager(self):
8383
self._program_create_wiz.eligibility_type = "default_eligibility"
84-
res = self._program_create_wiz._get_eligibility_manager(self.program["res_id"])
84+
res = self._program_create_wiz._get_eligibility_manager(self._program_action["params"]["program_id"])
8585

8686
self.assertIn("eligibility_managers", res)
8787

@@ -115,7 +115,7 @@ def test_06_create_program(self):
115115
"entitlement_item_ids": [Command.create({"product_id": self.product.id, "quantity": 1})],
116116
}
117117
)
118-
program = new_wiz.create_program()
118+
action = new_wiz.create_program()
119119

120-
self.assertEqual(program["res_model"], "spp.program")
121-
self.assertIsNotNone(program)
120+
self.assertEqual(action["type"], "ir.actions.client")
121+
self.assertTrue(action["params"]["program_id"])

spp_programs/tests/test_spp_cycle_compliance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def setUpClass(cls):
2121
}
2222
)
2323
action = cls._test.create_program()
24-
cls.program = cls.env["spp.program"].browse(action["res_id"])
24+
cls.program = cls.env["spp.program"].browse(action["params"]["program_id"])
2525

2626
@classmethod
2727
def _create_individual(self, vals):

spp_programs/tests/test_spp_program_create_wizard_compliance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_01_create_program_without_compliance_manager(self):
1212
wizard = self.program_create_wizard({})
1313
wizard._check_compliance_manager_info()
1414
action = wizard.create_program()
15-
program = self.env["spp.program"].browse(action["res_id"])
15+
program = self.env["spp.program"].browse(action["params"]["program_id"])
1616
self.assertFalse(
1717
bool(program.compliance_manager_ids),
1818
"Should not create compliance manager for new program!",
@@ -38,7 +38,7 @@ def test_03_create_program_default_compliance_manager(self):
3838
}
3939
)
4040
action = wizard.create_program()
41-
program = self.env["spp.program"].browse(action["res_id"])
41+
program = self.env["spp.program"].browse(action["params"]["program_id"])
4242
self.assertTrue(
4343
bool(program.compliance_manager_ids),
4444
"Should create compliance manager for new program!",

spp_programs/views/managers/eligibility_manager_view.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Part of OpenSPP. See LICENSE file for full copyright and licensing details.
6767
<field name="program_id" invisible="1" />
6868
</div>
6969

70-
<group string="Geographic Targeting" name="geographic_targeting" colspan="4" col="4">
70+
<group string="Geographic Targeting" name="geographic_targeting" colspan="4" col="4" invisible="1">
7171
<field
7272
name="admin_area_ids"
7373
widget="many2many_tags"

spp_programs/wizard/create_program_wizard.py

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -366,72 +366,73 @@ def _insert_domain_operator(self, domain):
366366
return new_domain
367367

368368
def create_program(self):
369+
self.ensure_one()
369370
self._check_required_fields()
370-
for rec in self:
371-
program_vals = rec.get_program_vals()
372-
program = self.env["spp.program"].with_context(skip_default_managers=True).create(program_vals)
373371

374-
program_id = program.id
375-
vals = {}
372+
program_vals = self.get_program_vals()
373+
program = self.env["spp.program"].with_context(skip_default_managers=True).create(program_vals)
376374

377-
# Set Default Eligibility Manager settings
378-
vals.update(rec._get_eligibility_manager(program_id))
375+
program_id = program.id
376+
vals = {}
379377

380-
# Set Default Cycle Manager settings
381-
# Add a new record to default cycle manager model
378+
# Set Default Eligibility Manager settings
379+
vals.update(self._get_eligibility_manager(program_id))
382380

383-
cycle_manager_default_val = rec.get_cycle_manager_default_val(program_id)
384-
def_mgr = self.env["spp.cycle.manager.default"].create(cycle_manager_default_val)
381+
# Set Default Cycle Manager settings
382+
# Add a new record to default cycle manager model
385383

386-
# Add a new record to cycle manager parent model
384+
cycle_manager_default_val = self.get_cycle_manager_default_val(program_id)
385+
def_mgr = self.env["spp.cycle.manager.default"].create(cycle_manager_default_val)
387386

388-
cycle_manager_val = rec.get_cycle_manager_val(program_id, def_mgr)
389-
mgr = self.env["spp.cycle.manager"].create(cycle_manager_val)
387+
# Add a new record to cycle manager parent model
390388

391-
vals.update({"cycle_manager_ids": [(4, mgr.id)]})
389+
cycle_manager_val = self.get_cycle_manager_val(program_id, def_mgr)
390+
mgr = self.env["spp.cycle.manager"].create(cycle_manager_val)
392391

393-
# Set Default Entitlement Manager
394-
vals.update(rec._get_entitlement_manager(program_id))
392+
vals.update({"cycle_manager_ids": [(4, mgr.id)]})
395393

396-
# Set Default Program Manager
397-
vals.update(rec._get_program_manager(program_id))
394+
# Set Default Entitlement Manager
395+
vals.update(self._get_entitlement_manager(program_id))
398396

399-
# Clean legacy aliases that are not real fields on spp.program
400-
vals.pop("eligibility_managers", None)
401-
vals.pop("cycle_managers", None)
402-
# Convert legacy entitlement_managers key to entitlement_manager_ids
403-
if "entitlement_managers" in vals:
404-
entitlement_managers = vals.pop("entitlement_managers")
405-
if "entitlement_manager_ids" not in vals:
406-
vals["entitlement_manager_ids"] = entitlement_managers
397+
# Set Default Program Manager
398+
vals.update(self._get_program_manager(program_id))
407399

408-
vals.update({"is_one_time_distribution": rec.is_one_time_distribution})
400+
# Clean legacy aliases that are not real fields on spp.program
401+
vals.pop("eligibility_managers", None)
402+
vals.pop("cycle_managers", None)
403+
# Convert legacy entitlement_managers key to entitlement_manager_ids
404+
if "entitlement_managers" in vals:
405+
entitlement_managers = vals.pop("entitlement_managers")
406+
if "entitlement_manager_ids" not in vals:
407+
vals["entitlement_manager_ids"] = entitlement_managers
409408

410-
# Complete the program data
411-
program.update(vals)
409+
vals.update({"is_one_time_distribution": self.is_one_time_distribution})
412410

413-
if rec.import_beneficiaries == "yes" or rec.is_one_time_distribution:
414-
rec.program_wizard_import_beneficiaries(program)
411+
# Complete the program data
412+
program.update(vals)
415413

416-
if rec.is_one_time_distribution:
417-
program.create_new_cycle()
414+
if self.import_beneficiaries == "yes" or self.is_one_time_distribution:
415+
self.program_wizard_import_beneficiaries(program)
418416

419-
view_id = self.env.ref("spp_programs.view_program_list_form")
420-
if rec.view_id:
421-
view_id = rec.view_id
417+
if self.is_one_time_distribution:
418+
program.create_new_cycle()
422419

423-
program.view_id = view_id.id
420+
view_id = self.env.ref("spp_programs.view_program_list_form")
421+
if self.view_id:
422+
view_id = self.view_id
424423

425-
# Open the newly created program
426-
return {
427-
"name": _("Programs"),
428-
"view_mode": "form",
429-
"res_model": "spp.program",
430-
"res_id": program_id,
424+
program.view_id = view_id.id
425+
426+
# Close modal and open program form using client action with async/await
427+
return {
428+
"type": "ir.actions.client",
429+
"tag": "open_program_close_modal",
430+
"params": {
431+
"program_id": program_id,
432+
"name": _("Program"),
431433
"view_id": view_id.id,
432-
"type": "ir.actions.act_window",
433-
"target": "current",
434-
}
434+
},
435+
}
435436

436437
def _get_default_eligibility_manager_val(self, program_id):
437438
return {

spp_programs/wizard/create_program_wizard.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ Part of OpenSPP. See LICENSE file for full copyright and licensing details.
261261
name="default_eligibility"
262262
invisible="eligibility_type != 'default_eligibility'"
263263
>
264-
<group colspan="4" string="Geographic Targeting">
264+
<group colspan="4" string="Geographic Targeting" invisible="1">
265265
<field
266266
name="admin_area_ids"
267267
colspan="4"

spp_programs/wizard/create_program_wizard_cel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ def create_program(self):
289289

290290
# Create dedicated compliance manager if CEL compliance is enabled
291291
if self.enable_compliance_cel and self.compliance_cel_expression:
292-
program = self.env["spp.program"].browse(action["res_id"])
292+
program = self.env["spp.program"].browse(action["params"]["program_id"])
293293
self._create_cel_compliance_manager(program)
294294

295295
return action

0 commit comments

Comments
 (0)