FlexiRule Docs
Document Action: Architecture Reference
Class structure, Resource Mapper internals, and mode dispatch logic for the Document Action.
Document Action: Architecture Reference#
Purpose#
The Document Action implementation abstracts Frappe’s CRUD operations into a declarative mapping-based engine. It centralizes document manipulation logic to ensure consistent application of permissions, background enqueuing, and context-aware value resolution.
Class Structure#
DocumentActionHandler(ActionHandler)#
- Responsibility: The primary singleton handler registered in the
HandlerRegistry. - Key Methods:
execute(): Orchestrates the overall lifecycle, applies input mappings, and dispatches to mode handlers._create_new(): Constructs document payloads and handlesis_asyncenqueuing._update_existing(): Handles targeted record modification._apply_table_mappings(): Implements the recursive row-mapping engine._get_same_field_mappings(): Implements field-matching logic between source and target.
Execution Pipeline#
- Registry Lookup:
RuleEngineidentifies the action type and fetches theDocumentActionHandlerinstance. - Mapping Layer:
- Scalar Mappings: Resolved via
_resolve_field_mappingsorcompiled_scalars(pre-compiled Python dict). - Static Values: Merged last to ensure explicit configuration overrides dynamic discovery.
- Scalar Mappings: Resolved via
- Table Engine:
- Iterates over
table_mappings. - Resolves the source collection (usually a list of dicts from
docorvars). - For each row:
- Creates a
row_contextwithitem(current row) andloopmetadata. - Evaluates
condition(inclusion check) andfilter(exclusion check). - Applies field-level assignments to the row payload.
- Appends the result to the parent document via
doc.append().
- Creates a
- Iterates over
- Dispatch:
- Sync:
frappe.get_doc(data).insert()/save(). - Async:
frappe.enqueue("..._async_create_doc", doc_data=data).
- Sync:
Context Mutation Model#
- Direct Memory Mutation: For
Update Existing, the handler performsdoc.set(field, value)on a loaded object. - Persistence Strategy: Mutations are not committed to the database until the explicit
.insert()or.save()call at the end of the mode handler. - Context Injection: The resulting document (post-save) is returned to the engine and injected into the
execution_context(e.g.,vars.my_result) usingapply_output_mapping.
Dependencies#
- Rule Engine Core: Relies on
HandlerRegistryfor registration. - Value Resolver: Uses
_safe_eval(inheriting fromActionHandler) for Python expression evaluation. - Permissions: Depends on
flexirule.ruleflow.core.permissions.can_skip_permissionsfor role-based security bypassing. - Utils: Uses
flexirule.ruleflow.utils.mapping.apply_input_mappingfor pre-execution config hydration.
Extension Points#
- Action Policies: Developers can override operation-level policies (like
required_config_keys) inflexirule/ruleflow/core/contracts.py. - Custom Resolvers: Custom Jinja filters or Python locals can be added to
_build_template_contextin the baseActionHandlerto make them available to Document Action mappings.
Internal Events#
- Background Task: Triggers a
frappe.enqueueevent for asynchronous creation. - Standard Hooks: Indirectly triggers all Frappe document lifecycle hooks (
before_insert,after_save, etc.) for the target DocType.
Source Files#
- Backend:
flexirule/ruleflow/core/action_handlers/create_doc.py - Frontend:
flexirule/public/js/flexirule/rule_builder/components/rule_config/types/DocumentActionConfig.vue - Contract:
flexirule/ruleflow/core/contracts.py
Was this page helpful?