Skip to content

Commit

Permalink
[IMP] l10n_it_fiscalcode: Configurable uniqueness constraint
Browse files Browse the repository at this point in the history
  • Loading branch information
SirAionTech authored and OCA-git-bot committed Dec 9, 2024
1 parent e095f39 commit 4e31bba
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 22 deletions.
14 changes: 14 additions & 0 deletions l10n_it_fiscalcode/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ Installare il modulo Python:
Install the Python package:
`codicefiscale <https://pypi.python.org/pypi/codicefiscale>`__.

Configuration
=============

**Italiano**

Per controllare che i codici fiscali siano unici in una stessa azienda,
abilitare "Il codice fiscale è unico" in Fatturazione > Configurazione >
Impostazioni.

**English**

In order to check that fiscal codes are unique within the same company,
enable "Tax code is unique" in Invoicing > Configuration > Settings.

Usage
=====

Expand Down
1 change: 1 addition & 0 deletions l10n_it_fiscalcode/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"view/report_invoice_document.xml",
"wizard/compute_fc_view.xml",
"view/company_view.xml",
"view/res_config_settings_views.xml",
],
"installable": True,
}
1 change: 1 addition & 0 deletions l10n_it_fiscalcode/model/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import res_config_settings
from . import res_partner
from . import res_city_it_code
from . import res_company
14 changes: 14 additions & 0 deletions l10n_it_fiscalcode/model/res_company.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@ class ResCompany(models.Model):
fiscalcode = fields.Char(
related="partner_id.fiscalcode", store=True, readonly=False
)
l10n_it_fiscalcode_check_uniqueness = fields.Boolean(
string="Fiscal code is unique",
help="When the fiscal code of a partner is edited, raise an error "
"if there is another partner with the same fiscal code.",
)

def l10n_it_fiscalcode_check_uniqueness_constraint(self):
"""Check the fiscal code of all the partners in `self`."""
partners = self.env["res.partner"].search(
[
("company_id", "in", [False] + self.ids),
]
)
partners._l10n_it_fiscalcode_constrain_uniqueness()
17 changes: 17 additions & 0 deletions l10n_it_fiscalcode/model/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 Simone Rubino - Aion Tech
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

l10n_it_fiscalcode_check_uniqueness = fields.Boolean(
related="company_id.l10n_it_fiscalcode_check_uniqueness",
readonly=False,
)

def l10n_it_fiscalcode_check_uniqueness_constraint(self):
"""Check the fiscal code of all the partners in current company."""
self.company_id.l10n_it_fiscalcode_check_uniqueness_constraint()

Check warning on line 17 in l10n_it_fiscalcode/model/res_config_settings.py

View check run for this annotation

Codecov / codecov/patch

l10n_it_fiscalcode/model/res_config_settings.py#L17

Added line #L17 was not covered by tests
61 changes: 61 additions & 0 deletions l10n_it_fiscalcode/model/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,64 @@ def check_fiscalcode(self):
def _fiscalcode_changed(self):
if self.fiscalcode:
self.fiscalcode = self.fiscalcode.upper()

@api.model
def _l10n_it_fiscalcode_build_uniqueness_constraint_error(self, error_dict):
"""Create the error message for uniqueness constraint."""
error_message_list = [
_("Multiple partners have the same fiscal code, please correct them.\n"),
]
for fiscal_code, partners in error_dict.items():
error_message_list.append(
_(
"%(fiscal_code)s: %(partners)s",
fiscal_code=fiscal_code,
partners=", ".join(partners.mapped("name")),
)
)
return "\n".join(error_message_list)

@api.constrains(
"fiscalcode",
)
def _l10n_it_fiscalcode_constrain_uniqueness(self):
"""
Partners in the same company must have different fiscal codes.
This check is only enabled for companies having "Fiscal code is unique".
"""
companies = self.company_id
if not companies:
companies = self.env["res.company"].search([])

for company in companies.filtered("l10n_it_fiscalcode_check_uniqueness"):
error_dict = {}
partner_groups = self.env["res.partner"].read_group(
[
("company_id", "in", [False, company.id]),
("fiscalcode", "!=", False),
],
[
"fiscalcode",
],
[
"fiscalcode",
],
)
for partner_group in partner_groups:
if partner_group["fiscalcode_count"] > 1:
error_partners = self.env["res.partner"].search(
partner_group["__domain"]
)
if self & error_partners:
# Only raise an error for partners we are checking
error_fiscal_code = partner_group["fiscalcode"]
error_dict[error_fiscal_code] = error_partners

if error_dict:
error_message = (
self._l10n_it_fiscalcode_build_uniqueness_constraint_error(
error_dict
)
)
raise ValidationError(error_message)
7 changes: 7 additions & 0 deletions l10n_it_fiscalcode/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
**Italiano**

Per controllare che i codici fiscali siano unici in una stessa azienda, abilitare "Il codice fiscale è unico" in Fatturazione > Configurazione > Impostazioni.

**English**

In order to check that fiscal codes are unique within the same company, enable "Tax code is unique" in Invoicing > Configuration > Settings.
58 changes: 36 additions & 22 deletions l10n_it_fiscalcode/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

/*
:Author: David Goodger ([email protected])
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -274,7 +275,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -300,7 +301,7 @@
span.pre {
white-space: pre }

span.problematic {
span.problematic, pre.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -379,17 +380,18 @@ <h1 class="title">ITA - Codice fiscale</h1>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#changelog" id="toc-entry-3">Changelog</a><ul>
<li><a class="reference internal" href="#section-1" id="toc-entry-4">16.0.1.0.0 (2022-11-11)</a></li>
<li><a class="reference internal" href="#section-2" id="toc-entry-5">16.0.1.0.1 (2022-11-16)</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-3">Usage</a></li>
<li><a class="reference internal" href="#changelog" id="toc-entry-4">Changelog</a><ul>
<li><a class="reference internal" href="#section-1" id="toc-entry-5">16.0.1.0.0 (2022-11-11)</a></li>
<li><a class="reference internal" href="#section-2" id="toc-entry-6">16.0.1.0.1 (2022-11-16)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-6">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-7">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-8">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-9">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-10">Maintainers</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-7">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-8">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-9">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-10">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-11">Maintainers</a></li>
</ul>
</li>
</ul>
Expand All @@ -403,8 +405,18 @@ <h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>Install the Python package:
<a class="reference external" href="https://pypi.python.org/pypi/codicefiscale">codicefiscale</a>.</p>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1>
<p><strong>Italiano</strong></p>
<p>Per controllare che i codici fiscali siano unici in una stessa azienda,
abilitare “Il codice fiscale è unico” in Fatturazione &gt; Configurazione &gt;
Impostazioni.</p>
<p><strong>English</strong></p>
<p>In order to check that fiscal codes are unique within the same company,
enable “Tax code is unique” in Invoicing &gt; Configuration &gt; Settings.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1>
<p><strong>Italiano</strong></p>
<p>Sulla scheda del partner fare clic sul pulsante <em>Calcola CF</em> per aprire
la procedura guidata relativa al calcolo del codice fiscale.</p>
Expand All @@ -413,7 +425,7 @@ <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
to the fiscal code computation.</p>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#toc-entry-3">Changelog</a></h1>
<h1><a class="toc-backref" href="#toc-entry-4">Changelog</a></h1>
<div class="line-block">
<div class="line">[ The change log. The goal of this file is to help readers</div>
<div class="line">understand changes between version. The primary audience is end users
Expand All @@ -425,39 +437,39 @@ <h1><a class="toc-backref" href="#toc-entry-3">Changelog</a></h1>
break the structure of the README.rst or other documents where this
fragment is included. ]</p>
<div class="section" id="section-1">
<h2><a class="toc-backref" href="#toc-entry-4">16.0.1.0.0 (2022-11-11)</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">16.0.1.0.0 (2022-11-11)</a></h2>
<ul class="simple">
<li>[MIG] Migration from Odoo 14.0 to 16.0</li>
<li>[IMP] Black, isort, prettier (pre-commit)</li>
</ul>
</div>
<div class="section" id="section-2">
<h2><a class="toc-backref" href="#toc-entry-5">16.0.1.0.1 (2022-11-16)</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">16.0.1.0.1 (2022-11-16)</a></h2>
<ul class="simple">
<li>[IMP] Add codicefiscale.isvalid() to improve fiscalcode validation</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-6">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#toc-entry-7">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/l10n-italy/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/l10n-italy/issues/new?body=module:%20l10n_it_fiscalcode%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-7">Credits</a></h1>
<h1><a class="toc-backref" href="#toc-entry-8">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-8">Authors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-9">Authors</a></h2>
<ul class="simple">
<li>Link IT s.r.l.</li>
<li>Apulia Software</li>
<li>Odoo Italia Network</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-9">Contributors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-10">Contributors</a></h2>
<ul class="simple">
<li>Davide Corio</li>
<li>Luca Subiaco &lt;<a class="reference external" href="mailto:subluca&#64;gmail.com">subluca&#64;gmail.com</a>&gt;</li>
Expand All @@ -482,9 +494,11 @@ <h2><a class="toc-backref" href="#toc-entry-9">Contributors</a></h2>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-10">Maintainers</a></h2>
<h2><a class="toc-backref" href="#toc-entry-11">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
Expand Down
101 changes: 101 additions & 0 deletions l10n_it_fiscalcode/tests/test_fiscalcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,104 @@ def test_fiscal_code_check_company_VAT_change_to_person(self):
# Assert
self.assertIn("fiscal code", exc_message)
self.assertIn("16 characters", exc_message)

def test_uniqueness_disabled(self):
"""If a company has no "Fiscal code is unique",
partners with the same fiscal code are allowed."""
# Arrange
fiscal_code = "RSSMRA84H04H501X"
company = self.env.company
# pre-condition
self.assertFalse(company.l10n_it_fiscalcode_check_uniqueness)

# Act
partners = self.env["res.partner"].create(
[
{
"name": "Test fiscal code uniqueness",
"fiscalcode": fiscal_code,
},
{
"name": "Test duplicated fiscal code",
"fiscalcode": fiscal_code,
},
]
)

# Assert
self.assertEqual(
partners[0].fiscalcode,
partners[1].fiscalcode,
)

def test_uniqueness_constraint(self):
"""If a company has "Fiscal code is unique",
partners with the same fiscal code are not allowed."""
# Arrange
partner_names = [
"Test same fiscal code",
"Test duplicated fiscal code",
]
fiscal_code = "RSSMRA84H04H501X"
company = self.env.company
company.l10n_it_fiscalcode_check_uniqueness = True
# pre-condition
self.assertTrue(company.l10n_it_fiscalcode_check_uniqueness)

# Act
with self.assertRaises(ValidationError) as ve:
self.env["res.partner"].create(
[
{
"name": partner_name,
"fiscalcode": fiscal_code,
}
for partner_name in partner_names
]
)
exc_message = ve.exception.args[0]

# Assert
self.assertIn("same fiscal code", exc_message)
self.assertIn(fiscal_code, exc_message)
for partner_name in partner_names:
self.assertIn(partner_name, exc_message)

def test_company_uniqueness_constraint(self):
"""Uniqueness constraint can be checked for the whole company."""
# Arrange
partner_names = [
"Test same fiscal code",
"Test duplicated fiscal code",
]
fiscal_code = "RSSMRA84H04H501X"
company = self.env["res.company"].create(
{
"name": "Test company",
"l10n_it_fiscalcode_check_uniqueness": False,
}
)
self.env["res.partner"].create(
[
{
"name": partner_name,
"fiscalcode": fiscal_code,
"company_id": company.id,
}
for partner_name in partner_names
]
)
company.l10n_it_fiscalcode_check_uniqueness = True
# pre-condition
self.assertTrue(company.l10n_it_fiscalcode_check_uniqueness)

# Act
with self.assertRaises(ValidationError) as ve:
company.l10n_it_fiscalcode_check_uniqueness_constraint()
exc_message = ve.exception.args[0]

# Assert
self.assertIn("same fiscal code", exc_message)
self.assertIn(fiscal_code, exc_message)
for partner_name in partner_names:
self.assertIn(partner_name, exc_message)
Loading

0 comments on commit 4e31bba

Please sign in to comment.