Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14.0][ADD] contract_exception #1159

Open
wants to merge 1 commit into
base: 14.0
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions contract_exception/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models, wizard
22 changes: 22 additions & 0 deletions contract_exception/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2024 Foodles (http://www.foodles.co/)
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
{
"name": "Contract Exception",
"version": "14.0.1.0.0",
"category": "Contract Management",
"author": "Odoo Community Association (OCA), Foodles",
"maintainers": [""],
"website": "https://github.com/OCA/contract",
"depends": [
"base_exception",
"contract",
],
"data": [
"security/ir.model.access.csv",
"data/contract_exception_data.xml",
"views/contract_views.xml",
"wizard/contract_exception_confirm_view.xml",
],
"license": "AGPL-3",
"installable": True,
}
16 changes: 16 additions & 0 deletions contract_exception/data/contract_exception_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo noupdate="1">
<record forcecreate="True" id="ir_cron_test_contract" model="ir.cron">
<field name="name">Test Contracts</field>
<field name="active" eval="False" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">20</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field name="model_id" ref="contract.model_contract_contract" />
<field name="state">code</field>
<field name="code">model.test_all_contracts()</field>
</record>
</odoo>
5 changes: 5 additions & 0 deletions contract_exception/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import (
contract,
contract_line,
exception_rule,
)
50 changes: 50 additions & 0 deletions contract_exception/models/contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright 2024 Foodles (https://www.foodles.co/).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import api, models


class Contract(models.Model):
_inherit = ["contract.contract", "base.exception"]
_name = "contract.contract"

@api.model
def create(self, vals):
record = super().create(vals)
record._contract_check_exception(vals)
return record

def write(self, vals):
result = super().write(vals)
self._contract_check_exception(vals)
return result

@api.model
def _reverse_field(self):
return "contract_ids"

def _fields_trigger_check_exception(self):
return ["ignore_exception", "contract_line_ids"]

def detect_exceptions(self):
all_exceptions = super().detect_exceptions()
lines = self.mapped("contract_line_ids")
all_exceptions += lines.detect_exceptions()
return all_exceptions

def _contract_check_exception(self, vals):
check_exceptions = any(
field in vals for field in self._fields_trigger_check_exception()
)
if check_exceptions:
self.detect_exceptions()

@api.model
def test_all_contracts(self):
contract_set = self.search([])
contract_set.detect_exceptions()
return True

@api.model
def _get_popup_action(self):
return self.env.ref("contract_exception.action_contract_exception_confirm")
25 changes: 25 additions & 0 deletions contract_exception/models/contract_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2024 Foodles (https://www.foodles.co/).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).


from odoo import api, fields, models


class ContractLine(models.Model):
_inherit = ["contract.line", "base.exception.method"]
_name = "contract.line"

ignore_exception = fields.Boolean(
related="contract_id.ignore_exception", store=True, string="Ignore Exceptions"
)

def _get_main_records(self):
return self.mapped("contract_id")

@api.model
def _reverse_field(self):
return "contract_ids"

def _detect_exceptions(self, rule):
records = super()._detect_exceptions(rule)
return records.mapped("contract_id")
22 changes: 22 additions & 0 deletions contract_exception/models/exception_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2024 Foodles (https://www.foodles.co/).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ExceptionRule(models.Model):
_inherit = "exception.rule"

contract_ids = fields.Many2many(
comodel_name="contract.contract", string="Contracts"
)
model = fields.Selection(
selection_add=[
("contract.contract", "Contract"),
("contract.line", "Contract line"),
],
ondelete={
"contract.contract": "cascade",
"contract.line": "cascade",
},
)
2 changes: 2 additions & 0 deletions contract_exception/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_contract_exception_confirm,contract.exception.confirm,model_contract_exception_confirm,base_exception.group_exception_rule_manager,1,1,1,1
1 change: 1 addition & 0 deletions contract_exception/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_contract
67 changes: 67 additions & 0 deletions contract_exception/tests/test_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2024 Foodles (https://www.foodles.co/).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from unittest.mock import patch

from odoo.tests import SavepointCase


class TestContract(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.customer = cls.env["res.partner"].create({"name": "Test Customer"})
cls.contract = cls.env["contract.contract"].create(
{"name": "Test Contract", "partner_id": cls.customer.id}
)

@patch("odoo.addons.contract_exception.models.contract.Contract.detect_exceptions")
@patch(
"odoo.addons.contract_exception."
"models.contract.Contract._fields_trigger_check_exception"
)
def test_contract_check_exception_with_field_that_trigger_exception(
self, mock_fields_trigger_check_exception, mock_detect_exceptions
):
mock_fields_trigger_check_exception.return_value = ["partner_id"]
self.contract._contract_check_exception({"partner_id": 1})
mock_detect_exceptions.assert_called_once()

@patch("odoo.addons.contract_exception.models.contract.Contract.detect_exceptions")
@patch(
"odoo.addons.contract_exception."
"models.contract.Contract._fields_trigger_check_exception"
)
def test_contract_check_exception_without_field_that_trigger_exception(
self, mock_fields_trigger_check_exception, mock_detect_exceptions
):
mock_fields_trigger_check_exception.return_value = []
self.contract._contract_check_exception({"partner_id": 1})
self.assertEqual(mock_detect_exceptions.call_count, 0)

def test_detect_exceptions(self):
rules = self.env["exception.rule"].create(
[
{
"name": "Test Rule",
"model": "contract.contract",
"code": "failed=True",
},
{
"name": "Test contract line Rule",
"model": "contract.line",
"code": "failed=True",
},
]
)
self.contract.contract_line_ids = [(0, 0, {"name": "Test Line"})]
exceptions = self.contract.detect_exceptions()
self.assertEqual(exceptions, rules.ids)

@patch("odoo.addons.contract_exception.models.contract.Contract.detect_exceptions")
def test_all_contracts(self, mock_detect_exceptions):
self.env["contract.contract"].test_all_contracts()
self.assertEqual(
self.env["contract.contract"].search_count([]),
mock_detect_exceptions.call_count,
)
84 changes: 84 additions & 0 deletions contract_exception/views/contract_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="action_contract_test_tree" model="ir.actions.act_window">
<field name="name">Contract Exception Rules</field>
<field name="res_model">exception.rule</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="base_exception.view_exception_rule_tree" />
<field
name="domain"
>[('model', 'in', ['contract.contract', 'contract.line'])]</field>
<field
name="context"
>{'active_test': False, 'default_model' : 'contract.contract'}</field>
</record>
<menuitem
action="action_contract_test_tree"
id="menu_contract_test"
sequence="90"
parent="account.account_management_menu"
groups="base_exception.group_exception_rule_manager"
/>
<record id="view_order_form" model="ir.ui.view">
<field name="name">contract_exception.view_contract_form</field>
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_form_view" />
<field name="arch" type="xml">
<sheet position="before">
<div
class="alert alert-danger"
role="alert"
style="margin-bottom:0px;"
attrs="{'invisible': [('exceptions_summary','=',False)]}"
>
<p>
<strong>There are exceptions on this contract:</strong>
</p>
<field name="exceptions_summary" />
<button
name="action_ignore_exceptions"
type="object"
class="btn-danger"
string="Ignore Exceptions"
help="Click here to be able to confirm this contract regardless of the exceptions."
groups="base_exception.group_exception_rule_manager"
/>
</div>
</sheet>
<xpath expr="//field[@name='contract_template_id']/.." position="inside">
<field name="ignore_exception" />
</xpath>
<xpath expr="//field[@name='contract_line_ids']/tree" position="inside">
<field name="ignore_exception" invisible="1" />
</xpath>
</field>
</record>
<record id="view_contract_tree" model="ir.ui.view">
<field name="name">contract_exception.view_order_tree</field>
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_tree_view" />
<field name="arch" type="xml">
<field name="name" position="after">
<field name="main_exception_id" />
</field>
</field>
</record>

<record id="contract_contract_search_view" model="ir.ui.view">
<field name="name">contract_exception.view_contracts_filter</field>
<field name="model">contract.contract</field>
<field name="inherit_id" ref="contract.contract_contract_search_view" />
<field name="arch" type="xml">
<filter name="group_by_date_end" position="after">
<separator orientation="vertical" />
<filter
icon="terp-emblem-important"
name="tofix"
string="Blocked"
domain="[('main_exception_id','!=',False)]"
/>
</filter>
</field>
</record>
</odoo>
1 change: 1 addition & 0 deletions contract_exception/wizard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import contract_exception_confirm, contract_manually_single_invoice
23 changes: 23 additions & 0 deletions contract_exception/wizard/contract_exception_confirm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2024 Foodles (https://www.foodles.co/).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ContractExceptionConfirm(models.TransientModel):
_name = "contract.exception.confirm"
_description = "Contract exception wizard"
_inherit = ["exception.rule.confirm"]

related_model_id = fields.Many2one(
comodel_name="contract.contract", string="Contract"
)

date = fields.Date(required=True)

def action_confirm(self):
self.ensure_one()
if self.ignore:
self.related_model_id.ignore_exception = True
self.related_model_id.generate_invoices_manually(self.date)
return super().action_confirm()
43 changes: 43 additions & 0 deletions contract_exception/wizard/contract_exception_confirm_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_contract_exception_confirm" model="ir.ui.view">
<field name="name">Contract Exceptions</field>
<field name="model">contract.exception.confirm</field>
<field name="arch" type="xml">
<form string="Can't generate invoice due to contract exception">
<group>

<field name="exception_ids" nolabel="1" colspan="4">
<tree>
<field name="name" />
<field name="description" />
</tree>
</field>
<newline />
<field name="ignore" groups='sales_team.group_sale_manager' />
<field name="date" />
</group>
<footer>
<button
name="action_confirm"
string="Confirm"
colspan="1"
type="object"
/>
<button class="oe_link" special="cancel" string="Cancel" />
</footer>
</form>
</field>
</record>
<record id="action_contract_exception_confirm" model="ir.actions.act_window">
<field name="name">Outstanding exceptions to manage</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">contract.exception.confirm</field>
<field name="view_mode">form</field>
<field
name="view_id"
ref="contract_exception.view_contract_exception_confirm"
/>
<field name="target">new</field>
</record>
</odoo>
18 changes: 18 additions & 0 deletions contract_exception/wizard/contract_manually_single_invoice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2024 Foodles (https://www.foodles.co/).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import models


class ContractManuallySingleInvoice(models.TransientModel):
_inherit = "contract.manually.single.invoice"

def create_invoice(self):
if (
self.contract_id.detect_exceptions()
and not self.contract_id.ignore_exception
):
action = self.contract_id._popup_exceptions()
action.get("context").update({"default_date": self.date})
return action
return self.contract_id.generate_invoices_manually(date=self.date)
1 change: 1 addition & 0 deletions oca_dependencies.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# See https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#oca_dependencies-txt
contract https://github.com/OCA/contract dixmit:14.0-contract-improve
Loading
Loading