diff --git a/sale_exception_portal/__init__.py b/sale_exception_portal/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/sale_exception_portal/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/sale_exception_portal/__manifest__.py b/sale_exception_portal/__manifest__.py new file mode 100644 index 00000000..79476897 --- /dev/null +++ b/sale_exception_portal/__manifest__.py @@ -0,0 +1,22 @@ +{ + 'name': 'Sale Exception Portal', + 'summary': 'Display sale exceptions on customer portal', + 'version': '16.0.1.0.0', + 'author': "Hibou Corp.", + 'category': 'Sale', + 'license': 'AGPL-3', + 'website': "https://hibou.io", + 'description': """ +Display sale exceptions on customer portal and prevent further action +""", + 'depends': [ + 'sale_exception', + ], + 'demo': [], + 'data': [ + 'views/sale_portal_templates.xml', + 'views/sale_views.xml', + ], + 'auto_install': False, + 'installable': True, +} diff --git a/sale_exception_portal/models/__init__.py b/sale_exception_portal/models/__init__.py new file mode 100644 index 00000000..8a0dc04e --- /dev/null +++ b/sale_exception_portal/models/__init__.py @@ -0,0 +1 @@ +from . import sale diff --git a/sale_exception_portal/models/sale.py b/sale_exception_portal/models/sale.py new file mode 100644 index 00000000..76874b3c --- /dev/null +++ b/sale_exception_portal/models/sale.py @@ -0,0 +1,17 @@ +from odoo import fields, models + + +class ExceptionRule(models.Model): + _inherit = 'exception.rule' + + website_description = fields.Text('Description for Website') + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + def _check_sale_order_exceptions(self): + exception_ids = self.detect_exceptions() + exceptions = self.env['exception.rule'].browse(exception_ids) + reasons = [{'title': ex.name, 'description': ex.website_description or ex.description} for ex in exceptions] + return reasons diff --git a/sale_exception_portal/tests/__init__.py b/sale_exception_portal/tests/__init__.py new file mode 100644 index 00000000..0098975e --- /dev/null +++ b/sale_exception_portal/tests/__init__.py @@ -0,0 +1 @@ +from . import test_check_so_exceptions diff --git a/sale_exception_portal/tests/test_check_so_exceptions.py b/sale_exception_portal/tests/test_check_so_exceptions.py new file mode 100644 index 00000000..7c0c3bae --- /dev/null +++ b/sale_exception_portal/tests/test_check_so_exceptions.py @@ -0,0 +1,43 @@ +from odoo.tests.common import TransactionCase + + +class TestCheckSOExceptions(TransactionCase): + def setUp(self): + super(TestCheckSOExceptions, self).setUp() + + self.azure_customer = self.browse_ref('base.res_partner_12') + + self.exception_rule = self.env['exception.rule'].create({ + 'name': 'No Azure', + 'description': 'No sales to Azure', + 'active': True, + 'model': 'sale.order', + 'exception_type': 'by_py_code', + 'code': 'failed = object.partner_id and object.partner_id.id == %d' % self.azure_customer.id + }) + + self.sale_product = self.browse_ref('product.product_product_5') + self.sale_product.standard_price = 100.0 + + def test_00_check_so_exceptions(self): + sale_order = self.env['sale.order'].create({ + 'partner_id': self.azure_customer.id, + 'order_line': [(0, 0, { + 'product_id': self.sale_product.id, + 'product_uom_qty': 1.0, + 'price_unit': 50.0, + })], + }) + + exceptions = sale_order._check_sale_order_exceptions() + self.assertEqual(len(exceptions), 1) + self.assertEqual(exceptions[0].get('description'), 'No sales to Azure') + + self.exception_rule.website_description = 'Different message for website' + exceptions = sale_order._check_sale_order_exceptions() + self.assertEqual(len(exceptions), 1) + self.assertEqual(exceptions[0].get('description'), 'Different message for website') + + self.exception_rule.active = False + exceptions = sale_order._check_sale_order_exceptions() + self.assertEqual(len(exceptions), 0) diff --git a/sale_exception_portal/views/sale_portal_templates.xml b/sale_exception_portal/views/sale_portal_templates.xml new file mode 100644 index 00000000..a3f7434b --- /dev/null +++ b/sale_exception_portal/views/sale_portal_templates.xml @@ -0,0 +1,75 @@ + + + + + + diff --git a/sale_exception_portal/views/sale_views.xml b/sale_exception_portal/views/sale_views.xml new file mode 100644 index 00000000..e228739a --- /dev/null +++ b/sale_exception_portal/views/sale_views.xml @@ -0,0 +1,15 @@ + + + + + exception.rule.form.inherit + exception.rule + + + + + + + + + diff --git a/sale_exception_user/__init__.py b/sale_exception_user/__init__.py new file mode 100644 index 00000000..455a4c33 --- /dev/null +++ b/sale_exception_user/__init__.py @@ -0,0 +1,3 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from . import wizard diff --git a/sale_exception_user/__manifest__.py b/sale_exception_user/__manifest__.py new file mode 100644 index 00000000..d41c61db --- /dev/null +++ b/sale_exception_user/__manifest__.py @@ -0,0 +1,23 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +{ + 'name': 'Sale Exception Rule User', + 'version': '16.0.1.0.0', + 'author': 'Hibou Corp.', + 'license': 'OPL-1', + 'category': 'Generic Modules', + 'summary': 'Allow users to ignore sale exceptions', + 'description': """ +Allow users to ignore sale exceptions +""", + 'website': 'https://hibou.io/', + 'depends': [ + 'base_exception_user', + 'sale_exception', + ], + 'data': [ + 'wizard/sale_exception_confirm_view.xml', + ], + 'installable': True, + 'auto_install': True, +} diff --git a/sale_exception_user/tests/__init__.py b/sale_exception_user/tests/__init__.py new file mode 100644 index 00000000..e236a89d --- /dev/null +++ b/sale_exception_user/tests/__init__.py @@ -0,0 +1,3 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from . import test_sale_exception_user diff --git a/sale_exception_user/tests/test_sale_exception_user.py b/sale_exception_user/tests/test_sale_exception_user.py new file mode 100644 index 00000000..4033df8d --- /dev/null +++ b/sale_exception_user/tests/test_sale_exception_user.py @@ -0,0 +1,59 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo.tests import Form, TransactionCase + + +class TestSaleException(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + groups = (cls.env.ref('base_exception_user.group_exception_rule_user') | + cls.env.ref('sales_team.group_sale_manager')) + user_dict = { + "name": "User test", + "login": "tua@example.com", + "password": "base-test-passwd", + "email": "armande.hruser@example.com", + "groups_id": [(6, 0, groups.ids)], + } + cls.user_test = cls.env['res.users'].create(user_dict) + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + + def test_sale_exception_user(self): + with self.with_user(self.user_test.login): + exception = self.env.ref("sale_exception.excep_no_zip").sudo() + exception.active = True + exception.allow_user_ignore = True + + partner = self.env.ref("base.res_partner_1") + partner.zip = False + p = self.env.ref("product.product_product_6") + so1 = self.env["sale.order"].create( + { + "partner_id": partner.id, + "partner_invoice_id": partner.id, + "partner_shipping_id": partner.id, + "order_line": [ + ( + 0, + 0, + { + "name": p.name, + "product_id": p.id, + "product_uom_qty": 2, + "product_uom": p.uom_id.id, + "price_unit": p.list_price, + }, + ) + ], + "pricelist_id": self.env.ref("product.list0").id, + } + ) + + action = so1.action_confirm() + wizard = Form(self.env[action['res_model']].with_user(self.user_test).with_context(action['context'])).save() + self.assertTrue(wizard.show_ignore_button) + action = wizard.action_ignore() + self.assertEqual(action.get('type'), 'ir.actions.act_window_close') + self.assertTrue(so1.ignore_exception) + self.assertEqual(so1.state, 'sale') diff --git a/sale_exception_user/wizard/__init__.py b/sale_exception_user/wizard/__init__.py new file mode 100644 index 00000000..5d468fa7 --- /dev/null +++ b/sale_exception_user/wizard/__init__.py @@ -0,0 +1,3 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from . import sale_exception_confirm diff --git a/sale_exception_user/wizard/sale_exception_confirm.py b/sale_exception_user/wizard/sale_exception_confirm.py new file mode 100644 index 00000000..b096f54b --- /dev/null +++ b/sale_exception_user/wizard/sale_exception_confirm.py @@ -0,0 +1,18 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo import fields, models + + +class SaleExceptionConfirm(models.TransientModel): + _inherit = 'sale.exception.confirm' + + def action_confirm(self): + res = super().action_confirm() + if self.ignore: + self.related_model_id.action_confirm() + return res + + def _action_ignore(self): + self.related_model_id.ignore_exception = True + self.related_model_id.action_confirm() + return super()._action_ignore() diff --git a/sale_exception_user/wizard/sale_exception_confirm_view.xml b/sale_exception_user/wizard/sale_exception_confirm_view.xml new file mode 100644 index 00000000..d3a7bbf2 --- /dev/null +++ b/sale_exception_user/wizard/sale_exception_confirm_view.xml @@ -0,0 +1,18 @@ + + + + + Sale Exceptions User + sale.exception.confirm + + + + + + +