Skip to content

Commit 54e4248

Browse files
docs(spp_import_match): update description and add QA testing guide
Align DESCRIPTION.md with actual code: fix sub-field example, clarify async chunking behavior, remove fabricated Queue Jobs menu path, add missing base.write() extension point. Add USAGE.md with 12 UI test cases covering rule configuration, import matching, conditional logic, async processing, and security.
1 parent 93fa4cb commit 54e4248

4 files changed

Lines changed: 890 additions & 60 deletions

File tree

spp_import_match/README.rst

Lines changed: 298 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,15 @@ Key Capabilities
3333

3434
- Define matching rules per model using field combinations to identify
3535
existing records
36-
- Match on sub-fields within related records (e.g., household ID within
37-
individual)
38-
- Apply conditional matching rules only when specific imported values
39-
are present
36+
- Match on sub-fields within related records (e.g., ``parent_id/name``)
37+
- Apply conditional matching rules only when a specific imported value
38+
is present
4039
- Skip duplicate creation or update existing records when matches are
4140
found
42-
- Process imports with more than 100 records asynchronously using
43-
``job_worker``
44-
- Clear one2many/many2many associations before update to prevent
45-
duplicate entries
41+
- Split imports exceeding 100 rows into chunks and process
42+
asynchronously via ``job_worker``
43+
- Strip falsy one2many/many2many values on write to prevent duplicate
44+
relational entries
4645

4746
Key Models
4847
~~~~~~~~~~
@@ -53,8 +52,8 @@ Key Models
5352
| ``spp.import.match`` | Matching rule configuration for a |
5453
| | specific model |
5554
+-----------------------------+----------------------------------------+
56-
| ``spp.import.match.fields`` | Individual fields used in a rule, |
57-
| | supports sub-fields |
55+
| ``spp.import.match.fields`` | Individual field in a rule, with |
56+
| | optional sub-field |
5857
+-----------------------------+----------------------------------------+
5958

6059
Configuration
@@ -63,23 +62,21 @@ Configuration
6362
After installing:
6463

6564
1. Navigate to **Registry > Configuration > Import Match**
66-
2. Create a new matching rule and select the target model (e.g.,
65+
2. Create a matching rule and select the target model (e.g.,
6766
``res.partner``)
6867
3. Add one or more fields to match on (e.g., national ID, or first name
6968
+ date of birth)
7069
4. Enable **Overwrite Match** to update existing records when matches
7170
are found
7271
5. For conditional matching, enable **Is Conditional** on a field and
73-
specify the expected imported value
72+
set the expected imported value
7473

7574
UI Location
7675
~~~~~~~~~~~
7776

7877
- **Menu**: Registry > Configuration > Import Match
79-
- **Import Dialog**: Matching applies automatically during CSV import
80-
via the standard Odoo import interface
81-
- **Queue Jobs**: Registry > Queue Jobs > Jobs (to monitor asynchronous
82-
imports)
78+
- **Import Dialog**: Select a matching rule and overwrite option from
79+
the import sidebar
8380

8481
Security
8582
~~~~~~~~
@@ -94,11 +91,11 @@ Extension Points
9491
~~~~~~~~~~~~~~~~
9592

9693
- Override ``spp.import.match._match_find()`` to customize matching
97-
logic for specific use cases
94+
logic
9895
- Override ``spp.import.match._usable_rules()`` to filter which rules
9996
apply based on context
100-
- Inherits ``base.load()`` to inject matching logic into all model
101-
imports
97+
- Overrides ``base.load()`` to inject matching into all model imports
98+
- Overrides ``base.write()`` to strip falsy one2many/many2many values
10299

103100
Dependencies
104101
~~~~~~~~~~~~
@@ -111,6 +108,288 @@ Dependencies
111108
.. contents::
112109
:local:
113110

111+
Usage
112+
=====
113+
114+
Prerequisites
115+
-------------
116+
117+
- The module **OpenSPP Import Match** is installed
118+
- You are logged in as a user with the **SPP Admin**
119+
(``spp_security.group_spp_admin``) role
120+
121+
Test 1: Create a Matching Rule
122+
------------------------------
123+
124+
**Steps:**
125+
126+
1. Navigate to **Registry > Configuration > Import Match**
127+
2. Click **New**
128+
3. Enter a name (e.g., "Match Partner by Name")
129+
4. In the **Match Details** tab, set **Model** to ``Contact``
130+
(res.partner)
131+
5. Verify that **Model Name** and **Model Description** auto-populate
132+
as ``res.partner`` and ``Contact``
133+
6. In the **Fields** list, click **Add a line**
134+
7. Select a non-relational field (e.g., ``Name``)
135+
8. Verify that the **Sub-Field** column is read-only (greyed out) for
136+
non-relational fields
137+
9. Leave **Is Conditional** unchecked and **Imported Value** empty
138+
10. Click **Save**
139+
140+
**Expected:**
141+
142+
- The rule appears in the list view with the name you entered
143+
- The list view shows a drag handle for reordering by sequence
144+
145+
Test 2: Verify Duplicate Field Validation
146+
-----------------------------------------
147+
148+
**Steps:**
149+
150+
1. Open the matching rule created in Test 1
151+
2. In the **Fields** list, click **Add a line**
152+
3. Select the same non-relational field (e.g., ``Name``) that already
153+
exists in the list
154+
155+
**Expected:**
156+
157+
- A validation error appears: "Field 'Name', already exists!"
158+
- The duplicate field is not added
159+
160+
Test 3: Sub-Field on Relational Fields
161+
--------------------------------------
162+
163+
**Steps:**
164+
165+
1. Create a new matching rule for model ``Contact`` (res.partner)
166+
2. In the **Fields** list, add a relational field (e.g., ``Parent``
167+
which is a Many2one)
168+
3. Verify that the **Sub-Field** column becomes editable and required
169+
4. Select a sub-field (e.g., ``Name``)
170+
5. Save the rule
171+
172+
**Expected:**
173+
174+
- The field's computed name displays as ``parent_id/name``
175+
(field/sub-field format)
176+
- The rule saves without error
177+
178+
Test 4: Model Change Clears Fields
179+
----------------------------------
180+
181+
**Steps:**
182+
183+
1. Open the matching rule created in Test 3
184+
2. Change the **Model** to a different model (e.g., ``Country``)
185+
3. Observe the **Fields** list
186+
187+
**Expected:**
188+
189+
- All previously configured fields are cleared from the list
190+
- The field domain updates to show only fields from the newly selected
191+
model
192+
193+
Test 5: Import with Matching — Skip Duplicates
194+
----------------------------------------------
195+
196+
**Steps:**
197+
198+
1. Create a matching rule for ``Contact`` with the ``Name`` field and
199+
**Overwrite Match** unchecked
200+
2. Create a contact manually with Name = "Test Import Match"
201+
3. Navigate to **Contacts** and click **Import records** (or use the
202+
gear/action menu)
203+
4. Upload a CSV file containing:
204+
::
205+
206+
name,email
207+
Test Import Match,updated@example.com
208+
Brand New Contact,new@example.com
209+
210+
5. In the import sidebar, locate the **Import Matching** section
211+
6. Select the matching rule you created from the dropdown
212+
7. Verify the **Overwrite Match** checkbox is unchecked
213+
8. Verify the helper text reads: "Matched records will be skipped."
214+
9. Click **Test** (dry run)
215+
216+
**Expected:**
217+
218+
- An info message appears: "1 to skip, 1 to create"
219+
- No records are modified yet
220+
221+
10. Click **Import**
222+
223+
**Expected:**
224+
225+
- A success notification appears: "1 skipped, 1 created"
226+
- The existing "Test Import Match" contact retains its original email
227+
(not updated)
228+
- A new "Brand New Contact" record is created with email
229+
``new@example.com``
230+
231+
Test 6: Import with Matching — Overwrite
232+
----------------------------------------
233+
234+
**Steps:**
235+
236+
1. Using the same matching rule from Test 5, re-import the same CSV
237+
2. In the import sidebar, select the matching rule
238+
3. Check the **Overwrite Match** checkbox
239+
4. Verify the helper text changes to: "Matched records will be
240+
overwritten with imported data."
241+
5. Click **Test** (dry run)
242+
243+
**Expected:**
244+
245+
- An info message appears showing counts for records to overwrite and to
246+
create
247+
248+
6. Click **Import**
249+
250+
**Expected:**
251+
252+
- A success notification with overwrite/create counts
253+
- The "Test Import Match" contact now has email ``updated@example.com``
254+
- The "Brand New Contact" record either has a second copy created or is
255+
matched (depending on whether a Name rule matched it from the previous
256+
import)
257+
258+
Test 7: Conditional Matching
259+
----------------------------
260+
261+
**Steps:**
262+
263+
1. Create a new matching rule for ``Contact`` with **Overwrite Match**
264+
checked
265+
2. Add the ``Name`` field to the match fields
266+
3. Check **Is Conditional** on the Name field
267+
4. Set **Imported Value** to "Test Import Match"
268+
5. Save the rule
269+
6. Import a CSV:
270+
::
271+
272+
name,email
273+
Test Import Match,conditional@example.com
274+
Some Other Name,other@example.com
275+
276+
7. Select this matching rule in the import sidebar
277+
278+
**Expected:**
279+
280+
- The row with name "Test Import Match" matches the condition and the
281+
existing record is overwritten
282+
- The row with name "Some Other Name" does not match the condition
283+
(imported value differs from "Test Import Match"), so the entire rule
284+
is skipped for that row and a new record is created
285+
286+
Test 8: Import Matching Dropdown Visibility
287+
-------------------------------------------
288+
289+
**Steps:**
290+
291+
1. Navigate to a model that has NO matching rules configured (e.g.,
292+
``Countries``)
293+
2. Open the import dialog
294+
295+
**Expected:**
296+
297+
- The **Import Matching** section does not appear in the sidebar (the
298+
dropdown is hidden when no rules exist for the model)
299+
300+
3. Navigate to a model that HAS matching rules (e.g., ``Contacts``)
301+
4. Open the import dialog
302+
303+
**Expected:**
304+
305+
- The **Import Matching** section appears with a dropdown listing all
306+
rules for that model
307+
- The default selection is "-- No Matching --"
308+
- The **Overwrite Match** checkbox is hidden until a rule is selected
309+
310+
Test 9: Overwrite Match Default from Rule
311+
-----------------------------------------
312+
313+
**Steps:**
314+
315+
1. Create a matching rule with **Overwrite Match** checked on the rule
316+
form
317+
2. Open the import dialog for the rule's model
318+
3. Select this rule from the **Import Matching** dropdown
319+
320+
**Expected:**
321+
322+
- The **Overwrite Match** checkbox is automatically checked (inherits
323+
the rule's default)
324+
- The user can uncheck it to override the default for this import
325+
326+
4. Select "-- No Matching --" from the dropdown
327+
328+
**Expected:**
329+
330+
- The **Overwrite Match** checkbox disappears
331+
332+
Test 10: Asynchronous Import (Large File)
333+
-----------------------------------------
334+
335+
**Steps:**
336+
337+
1. Create a matching rule for ``Contact`` with the ``Name`` field
338+
2. Prepare a CSV with more than 100 rows of contact data (101+ rows of
339+
data, not counting the header)
340+
3. Open the import dialog and upload the CSV
341+
4. Select the matching rule
342+
5. Click **Import** (not Test)
343+
344+
**Expected:**
345+
346+
- A notification appears: "Successfully added on Queue"
347+
- The browser navigates back to the previous page
348+
- The import is processed in the background via job worker
349+
- Check job status by navigating to **Settings > Technical > Queue Jobs
350+
> Jobs** (requires technical user access)
351+
352+
Test 11: Multiple Matches Error
353+
-------------------------------
354+
355+
**Steps:**
356+
357+
1. Create two contacts with the same email: ``duplicate@example.com``
358+
2. Create a matching rule for ``Contact`` using the ``Email`` field
359+
3. Import a CSV:
360+
::
361+
362+
email,name
363+
duplicate@example.com,Updated Name
364+
365+
4. Select the matching rule and click **Import**
366+
367+
**Expected:**
368+
369+
- An error is raised: "Multiple matches found for '...'" (where '...' is
370+
the name of the first matched record)
371+
- No records are modified
372+
373+
Test 12: Security — Non-Admin Access
374+
------------------------------------
375+
376+
**Steps:**
377+
378+
1. Log in as a user without the **SPP Admin** role
379+
2. Try to navigate to **Registry > Configuration > Import Match**
380+
381+
**Expected:**
382+
383+
- The **Import Match** menu item is not visible
384+
- The user cannot access the matching rule configuration
385+
386+
3. Open the import dialog for any model
387+
388+
**Expected:**
389+
390+
- The **Import Matching** section does not appear (the ``searchRead`` on
391+
``spp.import.match`` returns no results due to access rules)
392+
114393
Bug Tracker
115394
===========
116395

0 commit comments

Comments
 (0)