-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from mkumar-02/17.0-id-dedup
Added Registry ID Deduplication Module
- Loading branch information
Showing
23 changed files
with
1,146 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
================================= | ||
OpenG2P Registry ID Deduplication | ||
================================= | ||
|
||
.. | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! source digest: sha256:f31518db783800f8cac739f6f38ddd3ac1ea35c3c9a16426ae3e58d5a79a5b6f | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Alpha | ||
.. |badge2| image:: https://img.shields.io/badge/github-OpenG2P%2Fopeng2p--social--registry-lightgray.png?logo=github | ||
:target: https://github.com/OpenG2P/openg2p-social-registry/tree/17.0-develop/g2p_registry_id_deduplication | ||
:alt: OpenG2P/openg2p-social-registry | ||
|
||
|badge1| |badge2| | ||
|
||
G2P Registry ID Deduplication | ||
|
||
.. IMPORTANT:: | ||
This is an alpha version, the data model and design can change at any time without warning. | ||
Only for development or testing purpose, do not use in production. | ||
`More details on development status <https://odoo-community.org/page/development-status>`_ | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OpenG2P/openg2p-social-registry/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us to smash it by providing a detailed and welcomed | ||
`feedback <https://github.com/OpenG2P/openg2p-social-registry/issues/new?body=module:%20g2p_registry_id_deduplication%0Aversion:%2017.0-develop%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
~~~~~~~ | ||
|
||
* OpenG2P | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
`Manoj Kumar <[email protected]>` | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
||
This module is part of the `OpenG2P/openg2p-social-registry <https://github.com/OpenG2P/openg2p-social-registry/tree/17.0-develop/g2p_registry_id_deduplication>`_ project on GitHub. | ||
|
||
You are welcome to contribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Part of OpenG2P Social Registry. See LICENSE file for full copyright and licensing details. | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Part of OpenG2P Social Registry. See LICENSE file for full copyright and licensing details. | ||
{ | ||
"name": "OpenG2P Registry ID Deduplication", | ||
"category": "G2P", | ||
"version": "17.0.1.0.0", | ||
"sequence": 1, | ||
"author": "OpenG2P", | ||
"website": "https://openg2p.org", | ||
"license": "Other OSI approved licence", | ||
"development_status": "Alpha", | ||
"depends": [ | ||
"g2p_registry_group", | ||
"g2p_registry_individual", | ||
"g2p_registry_membership", | ||
], | ||
"external_dependencies": {}, | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/deduplication_criteria_view.xml", | ||
"views/deduplication_view.xml", | ||
"views/group_view.xml", | ||
"views/individual_view.xml", | ||
"views/res_config_view.xml", | ||
], | ||
"assets": { | ||
"web.assets_backend": [ | ||
"/g2p_registry_id_deduplication/static/src/js/duplicate_button.js", | ||
"/g2p_registry_id_deduplication/static/src/xml/duplicate_template.xml", | ||
], | ||
}, | ||
"demo": [], | ||
"images": [], | ||
"application": True, | ||
"installable": True, | ||
"auto_install": False, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Part of OpenG2P. See LICENSE file for full copyright and licensing details. | ||
|
||
from . import deduplication | ||
from . import registrant | ||
from . import res_config_settings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Part of OpenG2P. See LICENSE file for full copyright and licensing details. | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class G2PDeduplicationCriteria(models.Model): | ||
_name = "g2p.registry.id.deduplication_criteria" | ||
|
||
name = fields.Char(string="Criteria Name", required=True) | ||
grp_id_types = fields.Many2many("g2p.id.type", "g2p_registry_id_dedup_grp", string="ID Types") | ||
ind_id_types = fields.Many2many("g2p.id.type", "g2p_registry_id_dedup_ind", string="ID Types") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
# Part of OpenG2P. See LICENSE file for full copyright and licensing details. | ||
|
||
import logging | ||
|
||
from odoo import _, fields, models | ||
from odoo.exceptions import UserError | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class ResPartner(models.Model): | ||
_inherit = "res.partner" | ||
|
||
is_duplicate = fields.Boolean(default=False) | ||
|
||
def deduplicate_registrants(self): | ||
is_group = self._context.get("default_is_group") | ||
|
||
ind_id_types = self.get_id_types(id_field="ind_id_types") | ||
|
||
self.reset_duplicate_flag(is_group) | ||
|
||
if not is_group: | ||
ind_duplicate_ids = [] | ||
duplicates = self.get_duplicate_registrants( | ||
is_group, ind_id_types, group_condition="group_kind.name IS NULL" | ||
) | ||
|
||
for duplicate in duplicates: | ||
duplicate_partner_ids_str = duplicate.get("partner_ids") | ||
ind_duplicate_ids += duplicate_partner_ids_str.split(",") | ||
|
||
updated_ind_duplicate_ids = list(set(ind_duplicate_ids)) | ||
self.mark_registrant_as_duplicated(updated_ind_duplicate_ids) | ||
|
||
message = f"{len(updated_ind_duplicate_ids)} individuals" | ||
|
||
else: | ||
grp_id_types = self.get_id_types(id_field="grp_id_types") | ||
group_duplicate_ids = [] | ||
member_duplicate_ids = [] | ||
grouped_kinds = self.get_grouped_kinds() | ||
for kind in grouped_kinds: | ||
group_kind_name = kind.get("kind") | ||
group_ids_str = kind.get("group_ids") | ||
|
||
group_duplicates = self.get_duplicate_registrants( | ||
is_group, | ||
grp_id_types, | ||
group_condition=( | ||
f"group_kind.name = '{group_kind_name}'" | ||
if group_kind_name is not None | ||
else "group_kind.name IS NULL" | ||
), | ||
) | ||
|
||
# Group Duplicate | ||
for duplicate in group_duplicates: | ||
duplicate_partner_ids_str = duplicate.get("partner_ids") | ||
group_duplicate_ids += duplicate_partner_ids_str.split(",") | ||
|
||
updated_grp_duplicate_ids = list(set(group_duplicate_ids)) | ||
self.mark_registrant_as_duplicated(updated_grp_duplicate_ids) | ||
|
||
# Group Member Duplicate | ||
group_member_duplicates = self.get_duplicate_group_members(group_ids_str, grp_id_types) | ||
for member_duplicate in group_member_duplicates: | ||
duplicate_partner_ids_str = member_duplicate.get("partner_ids") | ||
member_duplicate_ids += duplicate_partner_ids_str.split(",") | ||
|
||
updated_member_duplicate_ids = list(set(member_duplicate_ids)) | ||
self.mark_registrant_as_duplicated(updated_member_duplicate_ids) | ||
|
||
if len(updated_grp_duplicate_ids) > 0 and len(updated_member_duplicate_ids) > 0: | ||
message = f"{len(updated_grp_duplicate_ids)} groups and \ | ||
{len(updated_member_duplicate_ids)} group members" | ||
elif len(updated_member_duplicate_ids) > 0: | ||
message = f"{len(updated_member_duplicate_ids)} group members" | ||
else: | ||
message = f"{len(updated_grp_duplicate_ids)} groups" | ||
|
||
return { | ||
"type": "ir.actions.client", | ||
"tag": "display_notification", | ||
"params": { | ||
"title": _("Duplicate"), | ||
"message": f"{message} are duplicated.", | ||
"sticky": False, | ||
"type": "success", | ||
"next": { | ||
"type": "ir.actions.act_window_close", | ||
}, | ||
}, | ||
} | ||
|
||
def get_id_types(self, id_field): | ||
id_types = [] | ||
|
||
dedup_criteria_id = ( | ||
self.env["ir.config_parameter"] | ||
.sudo() | ||
.get_param("g2p_registry_id_deduplication.dedup_criteria_id", default=None) | ||
) | ||
|
||
if not dedup_criteria_id: | ||
raise UserError(_("No deduplication criteria configured. Please configure it in the settings.")) | ||
|
||
dedup_criteria = self.env["g2p.registry.id.deduplication_criteria"].search( | ||
[("id", "=", dedup_criteria_id)], limit=1 | ||
) | ||
|
||
if not dedup_criteria: | ||
raise UserError(_("Deduplication configuration not found.")) | ||
|
||
for id_type in dedup_criteria[id_field]: | ||
id_types.append(id_type.name) | ||
|
||
if len(id_types) < 1: | ||
raise UserError(_("No ID Types found in the Deduplication Configuration.")) | ||
|
||
return tuple(id_types) if len(id_types) != 1 else f"('{id_types[0]}')" | ||
|
||
def mark_registrant_as_duplicated(self, partner_ids): | ||
for partner in partner_ids: | ||
registrant = self.browse(int(partner)) | ||
if registrant: | ||
registrant.update({"is_duplicate": True}) | ||
|
||
def reset_duplicate_flag(self, is_group): | ||
query = f""" | ||
UPDATE res_partner | ||
SET is_duplicate = FALSE | ||
WHERE is_registrant = TRUE AND is_group = {is_group} | ||
""" | ||
_logger.debug("DB Query: %s" % query) | ||
|
||
try: | ||
self._cr.execute(query) # pylint: disable=sql-injection | ||
except Exception as e: | ||
_logger.error("Database Query Error: %s", e) | ||
raise UserError(_("Database Query Error: %s") % e) from None | ||
|
||
def get_grouped_kinds(self): | ||
query = """ | ||
SELECT | ||
group_kind.name AS kind, STRING_AGG(partner.id::text, ',') | ||
AS group_ids | ||
FROM res_partner AS partner | ||
LEFT JOIN g2p_group_kind AS group_kind ON group_kind.id = partner.kind | ||
WHERE is_registrant = TRUE AND is_group = TRUE | ||
GROUP BY group_kind.name | ||
""" | ||
|
||
try: | ||
self._cr.execute(query) # pylint: disable=sql-injection | ||
grouped_kinds = self._cr.dictfetchall() | ||
return grouped_kinds | ||
except Exception as e: | ||
_logger.error("Database Query Error: %s", e) | ||
raise UserError(_("Database Query Error: %s") % e) from None | ||
|
||
def get_duplicate_registrants(self, is_group, id_types, group_condition): | ||
query = f""" | ||
SELECT | ||
reg_id.value AS id_value, STRING_AGG(partner.id::text, ',') | ||
AS partner_ids | ||
FROM res_partner AS partner | ||
INNER JOIN g2p_reg_id AS reg_id ON reg_id.partner_id = partner.id | ||
JOIN g2p_id_type AS id_type ON id_type.id = reg_id.id_type | ||
LEFT JOIN g2p_group_kind AS group_kind ON group_kind.id = partner.kind | ||
WHERE is_registrant = TRUE AND id_type.name IN {id_types} AND is_group = {is_group} | ||
AND {group_condition} | ||
GROUP BY reg_id.value | ||
HAVING COUNT(partner.id) > 1 | ||
""" | ||
|
||
try: | ||
self._cr.execute(query) # pylint: disable=sql-injection | ||
individual_duplicates = self._cr.dictfetchall() | ||
return individual_duplicates | ||
except Exception as e: | ||
_logger.error("Database Query Error: %s", e) | ||
raise UserError(_("Database Query Error: %s") % e) from None | ||
|
||
def get_duplicate_group_members(self, group_ids, id_types): | ||
query = f""" | ||
SELECT | ||
reg_id.value AS id_value, STRING_AGG(group_member.group::text, ',') | ||
AS partner_ids | ||
FROM res_partner AS partner | ||
JOIN g2p_group_membership AS group_member ON partner.id = group_member.individual | ||
INNER JOIN g2p_reg_id AS reg_id ON reg_id.partner_id = partner.id | ||
JOIN g2p_id_type AS id_type ON id_type.id = reg_id.id_type | ||
WHERE partner.is_registrant = TRUE AND id_type.name IN {id_types} | ||
AND group_member.group IN ({group_ids}) | ||
GROUP BY reg_id.value | ||
HAVING COUNT(partner.id) > 1 | ||
""" | ||
|
||
try: | ||
self._cr.execute(query) # pylint: disable=sql-injection | ||
group_duplicates = self._cr.dictfetchall() | ||
return group_duplicates | ||
except Exception as e: | ||
_logger.error("Database Query Error: %s", e) | ||
raise UserError(_("Database Query Error: %s") % e) from None |
12 changes: 12 additions & 0 deletions
12
g2p_registry_id_deduplication/models/res_config_settings.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Part of OpenG2P. See LICENSE file for full copyright and licensing details. | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class RegistryConfig(models.TransientModel): | ||
_inherit = "res.config.settings" | ||
|
||
dedup_criteria_id = fields.Many2one( | ||
"g2p.registry.id.deduplication_criteria", | ||
config_parameter="g2p_registry_id_deduplication.dedup_criteria_id", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[build-system] | ||
requires = ["whool"] | ||
build-backend = "whool.buildapi" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
`Manoj Kumar <[email protected]>` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
G2P Registry ID Deduplication |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
g2p_registry_id_deduplication_criteria_admin,Registry Deduplication Criteria Admin Access,model_g2p_registry_id_deduplication_criteria,g2p_registry_base.group_g2p_admin,1,1,1,1 | ||
g2p_registry_id_deduplication_criteria_registrar,Registry Deduplication Criteria Registrar Access,model_g2p_registry_id_deduplication_criteria,,1,0,0,0 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.