Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions spp_programs/static/src/js/create_program.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,41 @@
import {ListController} from "@web/views/list/list_controller";
import {onWillStart} from "@odoo/owl";
import {patch} from "@web/core/utils/patch";
import {registry} from "@web/core/registry";
import {user} from "@web/core/user";
import {useService} from "@web/core/utils/hooks";

/**
* Client action to close modal and then open program form.
* This ensures proper sequencing with async/await.
*/
async function openProgramCloseModal(env, action) {
const actionService = env.services.action;
const programId = action.params?.program_id;
const programName = action.params?.name || "Program";
const viewId = action.params?.view_id || false;

// First close the modal
await actionService.doAction(
{type: "ir.actions.act_window_close"},
{clearBreadcrumbs: true}
);

// Then open the program form
if (programId) {
await actionService.doAction({
type: "ir.actions.act_window",
name: programName,
res_model: "spp.program",
res_id: programId,
views: [[viewId, "form"]],
target: "current",
});
}
Comment on lines 15 to 36

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The name of the action window is hardcoded as "Program", which isn't translatable. Also, the views parameter is hardcoded to use the default form view ([[false, "form"]]), which differs from the previous implementation that allowed a specific view_id to be used. To improve internationalization and restore the original flexibility, consider passing the name and view_id from the server-side action's parameters.

    const actionService = env.services.action;
    const programId = action.params?.program_id;
    const programName = action.params?.name || "Program";
    const viewId = action.params?.view_id || false;

    // First close the modal
    await actionService.doAction(
        {type: "ir.actions.act_window_close"},
        {clearBreadcrumbs: true}
    );

    // Then open the program form
    if (programId) {
        await actionService.doAction({
            type: "ir.actions.act_window",
            name: programName,
            res_model: "spp.program",
            res_id: programId,
            views: [[viewId, "form"]],
            target: "current",
        });
    }

}

registry.category("actions").add("open_program_close_modal", openProgramCloseModal);

patch(ListController.prototype, {
setup() {
super.setup();
Expand Down
18 changes: 9 additions & 9 deletions spp_programs/tests/test_create_program_wiz.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def setUp(self):
}
)

self.program = self._program_create_wiz.create_program()
self._program_action = self._program_create_wiz.create_program()
# self.cycle_manager_default = (
# self._program_create_wiz.create_cycle_manager_default(self.program.id)
# )
Expand Down Expand Up @@ -69,19 +69,19 @@ def test_02_create_program(self):
)
res = new_wiz.create_program()
self.assertEqual(type(res), dict, "Action should be in json format!")
for key in ("type", "res_model", "res_id"):
for key in ("type", "tag", "params"):
self.assertIn(key, res.keys(), f"Key `{key}` is missing!")
self.assertEqual(
res["type"],
"ir.actions.act_window",
"ir.actions.client",
"Action for program should be returned!",
)
self.assertEqual(res["res_model"], "spp.program", "Action for program should be return!")
self.assertTrue(res["res_id"], "New record for program should be existed!")
self.assertEqual(res["tag"], "open_program_close_modal", "Client action tag should match!")
self.assertTrue(res["params"]["program_id"], "New record for program should be existed!")

def test_03_get_eligibility_manager(self):
self._program_create_wiz.eligibility_type = "default_eligibility"
res = self._program_create_wiz._get_eligibility_manager(self.program["res_id"])
res = self._program_create_wiz._get_eligibility_manager(self._program_action["params"]["program_id"])

self.assertIn("eligibility_managers", res)

Expand Down Expand Up @@ -115,7 +115,7 @@ def test_06_create_program(self):
"entitlement_item_ids": [Command.create({"product_id": self.product.id, "quantity": 1})],
}
)
program = new_wiz.create_program()
action = new_wiz.create_program()

self.assertEqual(program["res_model"], "spp.program")
self.assertIsNotNone(program)
self.assertEqual(action["type"], "ir.actions.client")
self.assertTrue(action["params"]["program_id"])
2 changes: 1 addition & 1 deletion spp_programs/tests/test_spp_cycle_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def setUpClass(cls):
}
)
action = cls._test.create_program()
cls.program = cls.env["spp.program"].browse(action["res_id"])
cls.program = cls.env["spp.program"].browse(action["params"]["program_id"])

@classmethod
def _create_individual(self, vals):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_01_create_program_without_compliance_manager(self):
wizard = self.program_create_wizard({})
wizard._check_compliance_manager_info()
action = wizard.create_program()
program = self.env["spp.program"].browse(action["res_id"])
program = self.env["spp.program"].browse(action["params"]["program_id"])
self.assertFalse(
bool(program.compliance_manager_ids),
"Should not create compliance manager for new program!",
Expand All @@ -38,7 +38,7 @@ def test_03_create_program_default_compliance_manager(self):
}
)
action = wizard.create_program()
program = self.env["spp.program"].browse(action["res_id"])
program = self.env["spp.program"].browse(action["params"]["program_id"])
self.assertTrue(
bool(program.compliance_manager_ids),
"Should create compliance manager for new program!",
Expand Down
2 changes: 1 addition & 1 deletion spp_programs/views/managers/eligibility_manager_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Part of OpenSPP. See LICENSE file for full copyright and licensing details.
<field name="program_id" invisible="1" />
</div>

<group string="Geographic Targeting" name="geographic_targeting" colspan="4" col="4">
<group string="Geographic Targeting" name="geographic_targeting" colspan="4" col="4" invisible="1">
<field
name="admin_area_ids"
widget="many2many_tags"
Expand Down
95 changes: 48 additions & 47 deletions spp_programs/wizard/create_program_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,72 +366,73 @@ def _insert_domain_operator(self, domain):
return new_domain

def create_program(self):
self.ensure_one()
self._check_required_fields()
for rec in self:
program_vals = rec.get_program_vals()
program = self.env["spp.program"].with_context(skip_default_managers=True).create(program_vals)

program_id = program.id
vals = {}
program_vals = self.get_program_vals()
program = self.env["spp.program"].with_context(skip_default_managers=True).create(program_vals)

# Set Default Eligibility Manager settings
vals.update(rec._get_eligibility_manager(program_id))
program_id = program.id
vals = {}

# Set Default Cycle Manager settings
# Add a new record to default cycle manager model
# Set Default Eligibility Manager settings
vals.update(self._get_eligibility_manager(program_id))

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

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

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

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

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

# Set Default Program Manager
vals.update(rec._get_program_manager(program_id))
# Set Default Entitlement Manager
vals.update(self._get_entitlement_manager(program_id))

# Clean legacy aliases that are not real fields on spp.program
vals.pop("eligibility_managers", None)
vals.pop("cycle_managers", None)
# Convert legacy entitlement_managers key to entitlement_manager_ids
if "entitlement_managers" in vals:
entitlement_managers = vals.pop("entitlement_managers")
if "entitlement_manager_ids" not in vals:
vals["entitlement_manager_ids"] = entitlement_managers
# Set Default Program Manager
vals.update(self._get_program_manager(program_id))

vals.update({"is_one_time_distribution": rec.is_one_time_distribution})
# Clean legacy aliases that are not real fields on spp.program
vals.pop("eligibility_managers", None)
vals.pop("cycle_managers", None)
# Convert legacy entitlement_managers key to entitlement_manager_ids
if "entitlement_managers" in vals:
entitlement_managers = vals.pop("entitlement_managers")
if "entitlement_manager_ids" not in vals:
vals["entitlement_manager_ids"] = entitlement_managers

# Complete the program data
program.update(vals)
vals.update({"is_one_time_distribution": self.is_one_time_distribution})

if rec.import_beneficiaries == "yes" or rec.is_one_time_distribution:
rec.program_wizard_import_beneficiaries(program)
# Complete the program data
program.update(vals)

if rec.is_one_time_distribution:
program.create_new_cycle()
if self.import_beneficiaries == "yes" or self.is_one_time_distribution:
self.program_wizard_import_beneficiaries(program)

view_id = self.env.ref("spp_programs.view_program_list_form")
if rec.view_id:
view_id = rec.view_id
if self.is_one_time_distribution:
program.create_new_cycle()

program.view_id = view_id.id
view_id = self.env.ref("spp_programs.view_program_list_form")
if self.view_id:
view_id = self.view_id

# Open the newly created program
return {
"name": _("Programs"),
"view_mode": "form",
"res_model": "spp.program",
"res_id": program_id,
program.view_id = view_id.id

# Close modal and open program form using client action with async/await
return {
"type": "ir.actions.client",
"tag": "open_program_close_modal",
"params": {
"program_id": program_id,
"name": _("Program"),
"view_id": view_id.id,
"type": "ir.actions.act_window",
"target": "current",
}
},
Comment on lines 430 to 434

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To support internationalization and allow for specific form views, it's a good practice to pass the translated window name and the calculated view_id to the client action. The JavaScript action can then use these parameters instead of hardcoded values.

            "params": {
                "program_id": program_id,
                "name": _("Program"),
                "view_id": view_id.id,
            },

}

def _get_default_eligibility_manager_val(self, program_id):
return {
Expand Down
2 changes: 1 addition & 1 deletion spp_programs/wizard/create_program_wizard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ Part of OpenSPP. See LICENSE file for full copyright and licensing details.
name="default_eligibility"
invisible="eligibility_type != 'default_eligibility'"
>
<group colspan="4" string="Geographic Targeting">
<group colspan="4" string="Geographic Targeting" invisible="1">
<field
name="admin_area_ids"
colspan="4"
Expand Down
2 changes: 1 addition & 1 deletion spp_programs/wizard/create_program_wizard_cel.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def create_program(self):

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

return action
Expand Down
2 changes: 1 addition & 1 deletion spp_programs/wizard/create_program_wizard_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def _check_required_fields(self):
def create_program(self):
action = super().create_program()
if self.enable_compliance_verification:
program = self.env["spp.program"].browse(action["res_id"])
program = self.env["spp.program"].browse(action["params"]["program_id"])
self._create_compliance_manager(program)
return action

Expand Down
Loading