ppm_create_project_from_template
Clone a project template into a new project for a specific customer, receiving IDs and names for the new project, portfolio, and program.
Instructions
Clone a project template and attach it to a customer (res.partner).
Returns the new project id, name, portfolio_id, and program_id.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| partner_id | Yes | ||
| template_id | Yes | ||
| project_name | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/qod_ppm_mcp/server.py:450-450 (registration)The `@mcp.tool()` decorator registers `ppm_create_project_from_template` as an MCP tool.
@mcp.tool() - src/qod_ppm_mcp/server.py:451-475 (handler)The handler function that clones a project template and attaches it to a customer (res.partner). It creates a `ppm.create.project.wizard` record with the given parameters, calls `action_create_project` on it, then reads and returns the new project's state.
def ppm_create_project_from_template( partner_id: int, template_id: int, project_name: str, ) -> dict[str, Any]: """Clone a project template and attach it to a customer (res.partner). Returns the new project id, name, portfolio_id, and program_id. """ wizard_id = client().execute_kw( "ppm.create.project.wizard", "create", [{"partner_id": partner_id, "template_id": template_id, "project_name": project_name}], ) action = client().call_action( "ppm.create.project.wizard", "action_create_project", [wizard_id] ) project_id = action.get("res_id") if isinstance(action, dict) else None if not project_id: raise RuntimeError("Template-create wizard did not return a project id") return _read_state( "project.project", project_id, ["id", "name", "partner_id", "portfolio_id", "program_id"], ) - src/qod_ppm_mcp/server.py:30-34 (helper)The `_read_state` helper used by the handler to fetch the new project's fields after creation.
def _read_state(model: str, rec_id: int, fields: list[str]) -> dict[str, Any]: rows = client().read(model, [rec_id], fields) if not rows: raise ValueError(f"{model} id={rec_id} not found") return rows[0] - src/qod_ppm_mcp/client.py:80-91 (helper)The `execute_kw` method on OdooClient used by the handler to create the wizard record.
def execute_kw( self, model: str, method: str, args: list[Any] | None = None, kwargs: dict[str, Any] | None = None, ) -> Any: return self._call( "object", "execute_kw", [self.db, self.uid, self.secret, model, method, args or [], kwargs or {}], ) - src/qod_ppm_mcp/client.py:122-124 (helper)The `call_action` method on OdooClient used by the handler to invoke `action_create_project` on the wizard.
def call_action(self, model: str, method: str, ids: list[int]) -> Any: """Invoke an `action_*` button method on the given record ids.""" return self.execute_kw(model, method, [ids])