diff --git a/.theia/launch.json b/.theia/launch.json index 287b3398..ab5720b4 100644 --- a/.theia/launch.json +++ b/.theia/launch.json @@ -68,6 +68,26 @@ "--test-enable", "--no-xmlrpc", "--stop-after-init"], "console": "integratedTerminal" }, + { + "name": "Odoo: INIT 'project_exception'", + "type": "python", + "request": "launch", + "program": "/opt/odoo/hibou-suite/odoo-run.py", + "args": ["-i", "project_exception", + "-u", "project_exception", + "--stop-after-init"], + "console": "integratedTerminal" + }, + { + "name": "Odoo: TEST 'project_exception'", + "type": "python", + "request": "launch", + "program": "/opt/odoo/hibou-suite/odoo-run.py", + "args": ["-i", "project_exception", + "-u", "project_exception", + "--test-enable", "--no-xmlrpc", "--stop-after-init"], + "console": "integratedTerminal" + }, { "name": "Odoo: server", "type": "python", diff --git a/project_exception/__init__.py b/project_exception/__init__.py index 3616b300..c7120225 100644 --- a/project_exception/__init__.py +++ b/project_exception/__init__.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. from . import models -from . import wizard \ No newline at end of file +from . import wizard diff --git a/project_exception/__manifest__.py b/project_exception/__manifest__.py index f892122d..2adb4ea1 100644 --- a/project_exception/__manifest__.py +++ b/project_exception/__manifest__.py @@ -1,35 +1,26 @@ -# -*- coding: utf-8 -*- +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. { 'name': "Project Exception Rule", - + 'version': '15.0.1.0.0', + 'author': "Hibou Corp.", + 'license': 'OPL-1', + 'category': 'Generic Modules', 'summary': """ Module for Project Exception Rule""", - 'description': """ The ability to run and trigger exceptions to block the moving of a task based on rules - """, - - 'author': "Hibou Corp.", + """, 'website': "http://www.hibou.io/", - - # Categories can be used to filter modules in modules listing - # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml - # for the full list - 'category': 'Generic Modules', - 'version': '15.0.1.0.0', - 'license': 'OPL-1', - - # any module necessary for this one to work correctly - 'depends': ['base_exception_user', 'project'], - - # always loaded + 'depends': [ + 'base_exception_user', + 'project' + ], 'data': [ 'security/ir.model.access.csv', 'views/project_views.xml', 'wizard/project_exception_confirm_views.xml', - ], - # only loaded in demonstration mode + ], 'demo': [ 'demo/project_exception_demo.xml', ], diff --git a/project_exception/demo/project_exception_demo.xml b/project_exception/demo/project_exception_demo.xml index 9a6b31a3..2dc5644d 100644 --- a/project_exception/demo/project_exception_demo.xml +++ b/project_exception/demo/project_exception_demo.xml @@ -2,11 +2,11 @@ - No Project Id - No Project Id + No Project Id on task + No Project Id on task 50 - project - if not project_id: failed=True + project.task + if not task.project_id.name: failed=True diff --git a/project_exception/models/__init__.py b/project_exception/models/__init__.py index 5305644d..449e23fb 100644 --- a/project_exception/models/__init__.py +++ b/project_exception/models/__init__.py @@ -1,3 +1,3 @@ -# -*- coding: utf-8 -*- +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from . import models \ No newline at end of file +from . import project \ No newline at end of file diff --git a/project_exception/models/models.py b/project_exception/models/models.py deleted file mode 100644 index 885bab9e..00000000 --- a/project_exception/models/models.py +++ /dev/null @@ -1,44 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from odoo import api, models, fields - - -class ExceptionRule(models.Model): - _inherit = 'exception.rule' - - model = fields.Selection( - selection_add=[ - ('stock.picking', 'Transfer'), - ], - ondelete={ - 'stock.picking': 'cascade', - }, - ) - picking_ids = fields.Many2many( - 'stock.picking', - string="Transfers") - -class Picking(models.Model): - _inherit = ['stock.picking', 'base.exception'] - _name = 'stock.picking' - _order = 'main_exception_id asc, priority desc, date asc, id desc' - - @api.model - def _exception_rule_eval_context(self, rec): - res = super(Picking, self)._exception_rule_eval_context(rec) - res['picking'] = rec - return res - - @api.model - def _reverse_field(self): - return 'picking_ids' - - def button_validate(self): - self.ensure_one() - if self.detect_exceptions(): - return self._popup_exceptions() - return super().button_validate() - - @api.model - def _get_popup_action(self): - return self.env.ref('stock_exception.action_stock_exception_confirm') diff --git a/project_exception/models/project.py b/project_exception/models/project.py new file mode 100644 index 00000000..de2e2fae --- /dev/null +++ b/project_exception/models/project.py @@ -0,0 +1,59 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo import api, models, fields + + +class ExceptionRule(models.Model): + _inherit = 'exception.rule' + + model = fields.Selection( + selection_add=[ + ('project.task', 'Task'), + ], + ondelete={ + 'project.task': 'cascade', + }, + ) + task_ids = fields.Many2many( + 'project.task', + string="Task") + + +class Task(models.Model): + _inherit = ['project.task', 'base.exception'] + _name = 'project.task' + _order = 'main_exception_id asc, sequence, name, id' + + @api.model + def create(self, values): + res = super().create(values) + res.detect_exceptions() + return res + + @api.model + def _exception_rule_eval_context(self, rec): + res = super(Task, self)._exception_rule_eval_context(rec) + res['task'] = rec + return res + + @api.model + def _reverse_field(self): + return 'task_ids' + + def write(self, vals): + if not vals.get('ignore_exception'): + for task in self: + if task.detect_exceptions(): + return self._popup_exceptions() + return super().write(vals) + + @api.model + def _get_popup_action(self): + return self.env.ref('project_exception.action_project_exception_confirm') + + def detect_exceptions(self): + res = False + if not self._context.get("detect_exceptions"): + self = self.with_context(detect_exceptions=True) + res = super(Task, self).detect_exceptions() + return res diff --git a/project_exception/security/ir.model.access.csv b/project_exception/security/ir.model.access.csv index 8177f81e..09d80192 100644 --- a/project_exception/security/ir.model.access.csv +++ b/project_exception/security/ir.model.access.csv @@ -1,2 +1,2 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_project_task_exception_confirm_project_task,project_task_exception.project_task_exception,model_project_task_exception_confirm,project.group_project_user,1,1,1,1 \ No newline at end of file +access_project_task_exception_confirm_user,project.exception.confirm user,model_project_exception_confirm,project.group_project_user,1,1,1,1 \ No newline at end of file diff --git a/project_exception/tests/test_project_exception.py b/project_exception/tests/test_project_exception.py index 6babeeab..9fa95c5f 100644 --- a/project_exception/tests/test_project_exception.py +++ b/project_exception/tests/test_project_exception.py @@ -12,32 +12,24 @@ class TestProjectException(common.TransactionCase): def test_project_task_creation_exception(self): exception = self.env.ref('project_exception.except_no_project_id') exception.active = True - # partner = self.env.ref('base.res_partner_12') # Azure Interior - # partner.zip = False - # p = self.env.ref('product.product_product_6') - # stock_location = self.env.ref('stock.stock_location_stock') - # customer_location = self.env.ref('stock.stock_location_customers') - # self.env['stock.quant']._update_available_quantity(p, stock_location, 100) - # delivery_order = self.env['stock.picking'].create({ - # 'partner_id': partner.id, - # 'picking_type_id': self.ref('stock.picking_type_out'), - # 'location_id': self.env.ref('stock.stock_location_stock').id, - # 'location_dest_id': self.env.ref('stock.stock_location_customers').id, - # 'move_line_ids': [(0, 0, {'product_id': p.id, - # 'product_uom_id': p.uom_id.id, - # 'qty_done': 3.0, - # 'location_id': stock_location.id, - # 'location_dest_id': customer_location.id})], - # }) + + task = self.env['project.task'].create({ + 'name': 'Test Task', + }) + # Created exceptions on create. + self.assertTrue(task.exception_ids) + + # Will return action on write, which may or not be followed. + action = task.write({ + 'name': 'Test Task - Test Written', + }) + self.assertTrue(task.exception_ids) + self.assertTrue(action) + self.assertEqual(action.get('res_model'), 'project.exception.confirm') - # validate delivery order - # action = delivery_order.button_validate() - # self.assertEqual(delivery_order.state, 'draft') - - # Simulation the opening of the wizard sale_exception_confirm and + # Simulation the opening of the wizard task_exception_confirm and # set ignore_exception to True - # stock_exception_confirm = Form(self.env[action['res_model']].with_context(action['context'])).save() - # stock_exception_confirm.ignore = True - # stock_exception_confirm.action_confirm() - # self.assertTrue(delivery_order.ignore_exception) - # self.assertEqual(delivery_order.state, 'done') + project_exception_confirm = Form(self.env[action['res_model']].with_context(action['context'])).save() + project_exception_confirm.ignore = True + project_exception_confirm.action_confirm() + self.assertTrue(task.ignore_exception) diff --git a/project_exception/views/project_views.xml b/project_exception/views/project_views.xml index 232dfafa..81298481 100644 --- a/project_exception/views/project_views.xml +++ b/project_exception/views/project_views.xml @@ -1,61 +1,62 @@ - - Stock Exception Rules + + Project Exception Rules exception.rule + tree,form - [('model', '=', 'stock.picking')] - {'active_test': False, 'default_model' : 'stock.picking'} + [('model', '=', 'project.task')] + {'active_test': False, 'default_model' : 'project.task'} - - stock.picking.form.inherit.exception - stock.picking - + + project.task.form.inherit.exception + project.task + - - + + - - stock.picking.tree.inherit.exception - stock.picking - + + project.task.tree.inherit.exception + project.task + - + - - stock.picking.internal.search.inherit.exception - stock.picking - + + project.task.search.form.inherit.exception + project.task + - + diff --git a/project_exception/wizard/__init__.py b/project_exception/wizard/__init__.py index c2c0dbf4..f10ee64b 100644 --- a/project_exception/wizard/__init__.py +++ b/project_exception/wizard/__init__.py @@ -1 +1,3 @@ -from . import project_exception_confim \ No newline at end of file +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from . import project_exception_confim diff --git a/project_exception/wizard/project_exception_confim.py b/project_exception/wizard/project_exception_confim.py index e69de29b..56d16935 100644 --- a/project_exception/wizard/project_exception_confim.py +++ b/project_exception/wizard/project_exception_confim.py @@ -0,0 +1,26 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo import api, fields, models + + +class ProjectExceptionConfirm(models.TransientModel): + _name = 'project.exception.confirm' + _inherit = ['exception.rule.confirm'] + _description = 'Project Exception Confirm Wizard' + + related_model_id = fields.Many2one('project.task', 'Task') + + def action_confirm(self): + self.ensure_one() + if self.ignore: + self.related_model_id.ignore_exception = True + res = super().action_confirm() + if self.ignore: + return True + else: + return res + + def _action_ignore(self): + self.related_model_id.ignore_exception = True + super()._action_ignore() + return True diff --git a/project_exception/wizard/project_exception_confirm_views.xml b/project_exception/wizard/project_exception_confirm_views.xml index e69de29b..5adeb0ec 100644 --- a/project_exception/wizard/project_exception_confirm_views.xml +++ b/project_exception/wizard/project_exception_confirm_views.xml @@ -0,0 +1,25 @@ + + + + + Project Exceptions Rules + project.exception.confirm + + primary + + +