Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions partner_state/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Partner State

Add three stats for partners:: 'Potential', 'Pending Approval' and 'Approved'.
Some information is required so that a partner can be approved. That
information is configured on: Sales/Settings/Address Book/Partner State fields.
information is configured on: Contacts > Configuration > Partner State Fields.

You can also configure on company if you want to use partner state on that
company or not.
Expand All @@ -34,9 +34,24 @@ Configuration
To configure this module, you need to:

#. Set "Use partner state " in the company.
#. Set the field that you required to approve partner in Sale/Configuration/Contact: Partner State Fields.
#. Set the field that you required to approve partner in Contacts > Configuration > Partner State Fields.
#. Set the permition to approve to the user.

Each line of Partner State Fields has these options:

* **Approval?**: the field is required to request the approval.
* **Changes?**: the changes of the field are logged in the chatter. It only
adds fields: the fields that Odoo already tracks are always logged, with or
without a line, and for them this option is checked and can not be unchecked.
* **Track?**: if the field changes on an approved or pending partner, the
partner goes back to Potential. Checking it also checks **Changes?**.
* **Block Edition**: the field can not be edited on an approved or pending
partner.

The fields that Odoo tracks on contacts by default are Name, Email, Phone,
Related Company, Salesperson, Tax ID and Inlined Complete Address. Other
installed modules can add more fields (for example, ``base_ux`` adds Active).

Usage
=====

Expand Down
11 changes: 11 additions & 0 deletions partner_state/i18n/es.po
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@ msgstr "Aprobado"
msgid "Block Edition"
msgstr "Bloquear Edición"

#. module: partner_state
#: model:ir.model.fields,field_description:partner_state.field_res_partner_state_field__chatter_tracking
msgid "Chatter Tracking"
msgstr "Registro en el chatter"

#. module: partner_state
#: model:ir.model.fields,field_description:partner_state.field_res_partner_state_field__changes
#: model_terms:ir.ui.view,arch_db:partner_state.view_partner_state_tree_2
msgid "Changes?"
msgstr "Cambios?"

Expand Down Expand Up @@ -186,6 +192,11 @@ msgstr "Seguir, y si cambia, volver a Potencial"
msgid "Track changes of the partner in the chatter box"
msgstr "Seguimiento de los cambios del Contacto en el cuadro de conversación"

#. module: partner_state
#: model:ir.model.fields,help:partner_state.field_res_partner_state_field__chatter_tracking
msgid "Fields with native tracking are always tracked."
msgstr "Los campos con trazabilidad nativa se registran siempre."

#. module: partner_state
#: model:ir.model.fields,field_description:partner_state.field_res_partner_state_field__track
msgid "Track?"
Expand Down
35 changes: 6 additions & 29 deletions partner_state/models/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,6 @@ def _compute_partner_state_enable(self):
partners.partner_state_enable = True

def write(self, vals):
initial_values = {}
state_fields_to_track = []

for line in self.env["res.partner.state_field"].search([("track", "=", True)]):
field_name = line.field_id.name
state_fields_to_track.append(field_name)
if field_name in vals:
for partner in self:
if partner.id not in initial_values:
initial_values[partner.id] = {}
initial_values[partner.id][field_name] = getattr(partner, field_name)

ResPartnerStateField = self.env["res.partner.state_field"]
for partner in self.filtered(lambda r: r.partner_state in ["approved", "pending"]):
partner_block_fields = ResPartnerStateField.search([("block_edition", "=", True)]).mapped("field_id.name")
Expand Down Expand Up @@ -105,20 +93,9 @@ def check_fields(self, field_type):
return ret

def _track_get_fields(self):
default_result = super()._track_get_fields()

fields_to_exclude = set()
fields_to_include = set()

for line in self.env["res.partner.state_field"].search([]):
field_name = line.field_id.name
if line.changes:
fields_to_include.add(field_name)
else:
fields_to_exclude.add(field_name)

final_result = set(default_result) - fields_to_exclude

final_result.update(fields_to_include)

return final_result
tracked_fields = set(super()._track_get_fields())
names = self.env["res.partner.state_field"].search([("changes", "=", True)]).mapped("field_id.name")
# fields_get() with an empty list returns every field
if names:
tracked_fields.update(self.fields_get(names, attributes=()))
return tracked_fields
20 changes: 20 additions & 0 deletions partner_state/models/res_partner_state_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,32 @@ class ResPartnerStateField(models.Model):
)
approval = fields.Boolean("Approval?", help="Required for Approval", default=True)
changes = fields.Boolean("Changes?", help="Track changes of the partner in the chatter box")
native_tracking = fields.Boolean(compute="_compute_native_tracking")
chatter_tracking = fields.Boolean(
compute="_compute_chatter_tracking",
inverse="_inverse_chatter_tracking",
help="Fields with native tracking are always tracked.",
)
track = fields.Boolean("Track?", help="Track and, if change, go back to Potencial", default=True)
block_edition = fields.Boolean(
help="Do not allow to edit this field if the partner is approved",
default=True,
)

@api.depends("field_id.tracking")
def _compute_native_tracking(self):
for line in self:
line.native_tracking = bool(line.field_id.tracking)

@api.depends("changes", "native_tracking")
def _compute_chatter_tracking(self):
for line in self:
line.chatter_tracking = line.changes or line.native_tracking

def _inverse_chatter_tracking(self):
for line in self.filtered(lambda x: not x.native_tracking):
line.changes = line.chatter_tracking

@api.onchange("track")
def _compute_changes(self):
if self.track:
Expand Down
1 change: 1 addition & 0 deletions partner_state/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
##############################################################################

from . import test_partner_state
from . import test_partner_state_tracking
80 changes: 80 additions & 0 deletions partner_state/tests/test_partner_state_tracking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################

from odoo.tests.common import TransactionCase


class TestPartnerStateTracking(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.StateField = cls.env["res.partner.state_field"]
cls.StateField.search([]).unlink()
cls.env.company.partner_state_enable = True
cls.partner = cls.env["res.partner"].create({"name": "Tracking Partner", "email": "[email protected]"})
# records created in the same transaction are not tracked until creation is finalized
cls._flush_tracking(cls.env)

@staticmethod
def _flush_tracking(env):
env.flush_all()
env.cr.precommit.run()

def _tracked_fields(self, vals):
"""Write vals on the partner and return the field names logged in the chatter."""
self.partner.message_ids.unlink()
self.partner.write(vals)
self._flush_tracking(self.env)
return set(self.partner.message_ids.tracking_value_ids.field_id.mapped("name"))

def _add_line(self, field_name, changes):
return self.StateField.create(
{
"field_id": self.env["ir.model.fields"]._get("res.partner", field_name).id,
"changes": changes,
"track": False,
"approval": False,
"block_edition": False,
}
)

def test_chatter_tracking_by_state_fields(self):
""" "Changes?" only adds fields to the chatter, it never removes standard ones.

- Without lines, the standard tracked fields are logged.
- A line with "Changes?" logs a field that is not tracked by default, and an
approved partner does not go back to potential.
- A line without "Changes?" does not stop logging a standard tracked field.
"""
with self.subTest("without lines, a standard tracked field is logged"):
self.assertEqual(self._tracked_fields({"email": "[email protected]"}), {"email"})

with self.subTest("a line with changes logs a field not tracked by default and keeps the partner approved"):
self._add_line("ref", changes=True)
self.partner.partner_state_approved()
self.assertEqual(self._tracked_fields({"ref": "REF-1", "email": "[email protected]"}), {"ref", "email"})
self.assertEqual(self.partner.partner_state, "approved")

with self.subTest("a line without changes keeps logging a standard tracked field"):
self._add_line("email", changes=False)
self.assertEqual(
self._tracked_fields({"ref": "REF-2", "email": "[email protected]"}),
{"ref", "email"},
)

def test_changes_column_for_standard_fields(self):
"""The "Changes?" column is checked and fixed for fields already tracked by Odoo."""
email_line = self._add_line("email", changes=False)
ref_line = self._add_line("ref", changes=False)

with self.subTest("a standard field shows changes checked even if the line has it unchecked"):
self.assertTrue(email_line.native_tracking)
self.assertTrue(email_line.chatter_tracking)

with self.subTest("another field shows and writes the stored changes value"):
self.assertFalse(ref_line.native_tracking)
self.assertFalse(ref_line.chatter_tracking)
ref_line.chatter_tracking = True
self.assertTrue(ref_line.changes)
4 changes: 3 additions & 1 deletion partner_state/views/res_partner_state_field_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
<list editable="top">
<field name="field_id" options="{'no_create': True, 'no_open': True}"/>
<field name="approval"/>
<field name="changes"/>
<field name="native_tracking" column_invisible="True"/>
<field name="changes" column_invisible="True"/>
<field name="chatter_tracking" string="Changes?" readonly="native_tracking"/>
<field name="track"/>
<field name="block_edition"/>
</list>
Expand Down
Loading