diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c5139e6d..25b5fd76 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,38 +1,21 @@ repos: - - repo: local + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 hooks: - id: check-added-large-files - name: Check for added large files - entry: check-added-large-files - language: system - id: check-toml - name: Check Toml - entry: check-toml - language: system - types: [toml] - id: check-yaml - name: Check Yaml - entry: check-yaml - language: system - types: [yaml] - id: end-of-file-fixer - name: Fix End of Files - entry: end-of-file-fixer - language: system - types: [text] - stages: [pre-commit, pre-push, manual] - id: trailing-whitespace - name: Trim Trailing Whitespace - entry: trailing-whitespace-fixer - language: system - types: [text] - stages: [pre-commit, pre-push, manual] + - repo: local + hooks: - id: pydoclint name: pydoclint entry: pydoclint - language: system + language: python types: [python] args: ["--generate-baseline=True"] + additional_dependencies: ["pydoclint"] - id: ruff name: ruff entry: ruff check @@ -44,7 +27,3 @@ repos: entry: ruff format language: python types_or: [python, pyi] - # - repo: https://github.com/pre-commit/mirrors-prettier - # rev: v4.0.0-alpha.8 - # hooks: - # - id: prettier diff --git a/modules/odf_data_quality_dashboard/__init__.py b/modules/odf_data_quality_dashboard/__init__.py new file mode 100644 index 00000000..0ce2eaf2 --- /dev/null +++ b/modules/odf_data_quality_dashboard/__init__.py @@ -0,0 +1,5 @@ +"""Odoo module for the Data Quality Dashboard.""" + +from . import models + +__all__ = ["models"] diff --git a/modules/odf_data_quality_dashboard/__manifest__.py b/modules/odf_data_quality_dashboard/__manifest__.py new file mode 100644 index 00000000..8b6a75ea --- /dev/null +++ b/modules/odf_data_quality_dashboard/__manifest__.py @@ -0,0 +1,20 @@ +"""Odoo module manifest for the Data Quality Dashboard.""" + +{ + "name": "ODF Data Quality Dashboard", + "summary": """ + Provides a dashboard to identify and manage data quality issues + after data import.""", + "author": "OdooDataFlow", + "website": "https://github.com/OdooDataFlow/odoo-data-flow", + "category": "Tools", + "version": "18.0.1.0.0", + "depends": ["base"], + "data": [ + "security/ir.model.access.csv", + "views/odf_data_quality_issue_views.xml", + "data/ir_cron_data.xml", + ], + "installable": True, + "application": True, +} diff --git a/modules/odf_data_quality_dashboard/data/ir_cron_data.xml b/modules/odf_data_quality_dashboard/data/ir_cron_data.xml new file mode 100644 index 00000000..15c1e36b --- /dev/null +++ b/modules/odf_data_quality_dashboard/data/ir_cron_data.xml @@ -0,0 +1,17 @@ + + + + + + Data Quality: Nightly Validation + + code + model._run_nightly_validation() + + 1 + days + -1 + + + + diff --git a/modules/odf_data_quality_dashboard/models/__init__.py b/modules/odf_data_quality_dashboard/models/__init__.py new file mode 100644 index 00000000..46888993 --- /dev/null +++ b/modules/odf_data_quality_dashboard/models/__init__.py @@ -0,0 +1,5 @@ +"""Models for the Data Quality Dashboard module.""" + +from . import odf_data_quality_issue + +__all__ = ["odf_data_quality_issue"] diff --git a/modules/odf_data_quality_dashboard/models/odf_data_quality_issue.py b/modules/odf_data_quality_dashboard/models/odf_data_quality_issue.py new file mode 100644 index 00000000..4b87d2c8 --- /dev/null +++ b/modules/odf_data_quality_dashboard/models/odf_data_quality_issue.py @@ -0,0 +1,85 @@ +"""Module to manage data quality issues.""" + +from datetime import datetime, timedelta + +from odoo import api, fields, models + + +class OdfDataQualityIssue(models.Model): + """Represents a data quality issue found in the system. + + This model stores records of data inconsistencies or errors, + allowing users to track and resolve them in a structured manner. + """ + + _name = "odf.data.quality.issue" + _description = "Data Quality Issue" + _order = "create_date desc" + + name = fields.Char( + string="Title", + required=True, + help="A concise summary of the data quality issue.", + ) + issue_type = fields.Char( + string="Issue Type", + required=True, + help="The category of the issue, e.g., 'Invalid VAT'.", + ) + related_record = fields.Reference( + string="Related Record", + selection=[("res.partner", "Partner"), ("product.product", "Product")], + help="A reference to the record that has the data quality issue.", + ) + status = fields.Selection( + [ + ("todo", "To Do"), + ("in_progress", "In Progress"), + ("done", "Done"), + ], + string="Status", + default="todo", + required=True, + help="The current stage of the issue resolution process.", + ) + notes = fields.Text( + string="Notes", + help="Detailed comments or notes about the issue.", + ) + + # ------------------------------------------------------------------------- + # Business Methods + # ------------------------------------------------------------------------- + @api.model + def _run_nightly_validation(self): + """Run all nightly data validation checks.""" + self._check_partners_with_missing_vat() + + @api.model + def _check_partners_with_missing_vat(self): + """Check for partners created in the last 24h with missing VAT.""" + yesterday = datetime.now() - timedelta(days=1) + # Search for companies created in the last 24 hours without a VAT + partners = self.env["res.partner"].search( + [ + ("is_company", "=", True), + ("create_date", ">=", yesterday), + ("vat", "=", False), + ] + ) + vals_list = [] + for partner in partners: + vals_list.append( + { + "name": f"Missing VAT for Partner: {partner.name}", + "issue_type": "Missing VAT", + "related_record": f"res.partner,{partner.id}", + "status": "todo", + "notes": ( + f"The partner '{partner.name}' is a company but does " + "not have a VAT number." + ), + } + ) + if vals_list: + self.create(vals_list) diff --git a/modules/odf_data_quality_dashboard/security/ir.model.access.csv b/modules/odf_data_quality_dashboard/security/ir.model.access.csv new file mode 100644 index 00000000..89e0284d --- /dev/null +++ b/modules/odf_data_quality_dashboard/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_odf_data_quality_issue_user,odf.data.quality.issue.user,model_odf_data_quality_issue,base.group_user,1,1,1,1 diff --git a/modules/odf_data_quality_dashboard/views/odf_data_quality_issue_views.xml b/modules/odf_data_quality_dashboard/views/odf_data_quality_issue_views.xml new file mode 100644 index 00000000..1ef6eab8 --- /dev/null +++ b/modules/odf_data_quality_dashboard/views/odf_data_quality_issue_views.xml @@ -0,0 +1,78 @@ + + + + + Data Quality Issues + odf.data.quality.issue + tree,kanban,form + +

+ No data quality issues found. Everything looks good! +

+
+
+ + + + odf.data.quality.issue.kanban + odf.data.quality.issue + + + + + +
+
+ +
+ Type: + +
+
+ Record: + +
+
+
+
+
+
+
+
+ + + + odf.data.quality.issue.form + odf.data.quality.issue + +
+ + + + + + + + + + + + + +
+
+
+ + + + + +
diff --git a/noxfile.py b/noxfile.py index d00df751..054af563 100644 --- a/noxfile.py +++ b/noxfile.py @@ -128,7 +128,8 @@ def precommit(session: nox.Session) -> None: "lint", external=True, ) - session.run("pre-commit", *args, external=True) + session.install("pre-commit") + session.run("pre-commit", *args) if args and args[0] == "install": activate_virtualenv_in_precommit_hooks(session) diff --git a/pyproject.toml b/pyproject.toml index b0059280..9df81d82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -193,6 +193,7 @@ exclude = [ [tool.ruff.lint.per-file-ignores] +"**/__manifest__.py" = ["B018"] "*/test_*.py" = ["S101"] "noxfile.py" = ["S101"] "**/conftest.py" = ["S101"]