diff --git a/spp_import_match/README.rst b/spp_import_match/README.rst index 2c4528cf..611fee98 100644 --- a/spp_import_match/README.rst +++ b/spp_import_match/README.rst @@ -393,6 +393,26 @@ Test 12: Security — Non-Admin Access Changelog ========= +19.0.2.0.2 +~~~~~~~~~~ + +- chore(views): hide the conditional-gate columns (``Is Conditional``, + ``Condition Field``, ``Condition Value``) from the match-rule fields + list — the schema and matching-engine wiring stay in place, but no + current import flow uses the gate, so the columns are kept out of the + UI until a real use case lands. + +19.0.2.0.1 +~~~~~~~~~~ + +- fix(matching): add a ``condition_field_id`` Many2one column to + ``spp.import.match.fields`` and rewrite the matching loop so + conditional rows act as pure gates — never added to the DB search + domain. Renames the IMPORTED VALUE column heading to **Condition + Value**. Fixes the case where a CSV-only metadata column (e.g. + ``data_source``) was being injected into the search domain and causing + zero matches. + 19.0.2.0.0 ~~~~~~~~~~ diff --git a/spp_import_match/__manifest__.py b/spp_import_match/__manifest__.py index 3c6a52ce..26fcef35 100644 --- a/spp_import_match/__manifest__.py +++ b/spp_import_match/__manifest__.py @@ -5,7 +5,7 @@ "name": "OpenSPP Import Match", "summary": "OpenSPP Import Match enhances data import processes by intelligently matching incoming records against existing data, preventing duplication and ensuring registry integrity. It provides configurable matching logic and supports seamless updates to existing records during bulk data onboarding.", "category": "OpenSPP/Integration", - "version": "19.0.2.0.0", + "version": "19.0.2.0.2", "sequence": 1, "author": "OpenSPP.org", "website": "https://github.com/OpenSPP/OpenSPP2", diff --git a/spp_import_match/models/import_match.py b/spp_import_match/models/import_match.py index 5ee26de6..51ab48b9 100644 --- a/spp_import_match/models/import_match.py +++ b/spp_import_match/models/import_match.py @@ -68,9 +68,21 @@ def _match_find(self, model, converted_row, imported_row): domain = list() for field in combination.field_ids: if field.is_conditional: - if imported_row[field.name] != field.imported_value: + # Conditional rows are pure *gates* — they decide whether + # the rule applies to this CSV row. The CSV column that + # carries the gate value is `condition_field_id` when + # set; otherwise we fall back to `field_id` for + # backwards compatibility with rules created before + # OP#991. Crucially, a conditional row is **not** added + # to the DB search domain — the gate column may be a + # CSV-only metadata field (e.g. `data_source`) that + # doesn't exist on the registrant model. + gate_field_name = field.condition_field_id.name if field.condition_field_id else field.field_id.name + if imported_row.get(gate_field_name) != field.imported_value: combination_valid = False break + continue + if field.field_id.name in converted_row: row_value = converted_row[field.field_id.name] # Skip matching on empty values to avoid false matches @@ -141,7 +153,29 @@ class SPPImportMatchFields(models.Model): match_id = fields.Many2one("spp.import.match", string="Match", ondelete="cascade") model_id = fields.Many2one(related="match_id.model_id") is_conditional = fields.Boolean() - imported_value = fields.Char(help="This will be used as a condition to disregard this field if matched") + condition_field_id = fields.Many2one( + "ir.model.fields", + string="Condition Field", + ondelete="cascade", + domain="[('model_id', '=', model_id)]", + help=( + "When `Is Conditional` is set, the rule only fires for CSV rows " + "whose value in this field equals `Condition Value`. The " + "condition field is used purely as a gate — it is **not** added " + "to the database search domain, so it can safely be a CSV-only " + "metadata column (e.g. `data_source`) that doesn't have data on " + "the registrant. Leave empty to fall back to the legacy " + "behaviour where `Field` is used as both the gate and the " + "search predicate." + ), + ) + imported_value = fields.Char( + string="Condition Value", + help=( + "Expected value of the condition field. The rule only applies " + "when the imported row's `Condition Field` matches this value." + ), + ) def _compute_name(self): for rec in self: diff --git a/spp_import_match/readme/HISTORY.md b/spp_import_match/readme/HISTORY.md index 4aaf9afe..01d95e79 100644 --- a/spp_import_match/readme/HISTORY.md +++ b/spp_import_match/readme/HISTORY.md @@ -1,3 +1,11 @@ +### 19.0.2.0.2 + +- chore(views): hide the conditional-gate columns (`Is Conditional`, `Condition Field`, `Condition Value`) from the match-rule fields list — the schema and matching-engine wiring stay in place, but no current import flow uses the gate, so the columns are kept out of the UI until a real use case lands. + +### 19.0.2.0.1 + +- fix(matching): add a `condition_field_id` Many2one column to `spp.import.match.fields` and rewrite the matching loop so conditional rows act as pure gates — never added to the DB search domain. Renames the IMPORTED VALUE column heading to **Condition Value**. Fixes the case where a CSV-only metadata column (e.g. `data_source`) was being injected into the search domain and causing zero matches. + ### 19.0.2.0.0 - Initial migration to OpenSPP2 diff --git a/spp_import_match/static/description/index.html b/spp_import_match/static/description/index.html index 3d48ccfc..dff79052 100644 --- a/spp_import_match/static/description/index.html +++ b/spp_import_match/static/description/index.html @@ -804,6 +804,28 @@