mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
Merge branch 'mig/16.0/sale_exception_website' into '16.0'
WIP: mig/16.0/sale_exception_website into 16.0 See merge request hibou-io/hibou-odoo/suite!1645
This commit is contained in:
1
sale_exception_portal/__init__.py
Normal file
1
sale_exception_portal/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
22
sale_exception_portal/__manifest__.py
Normal file
22
sale_exception_portal/__manifest__.py
Normal file
@@ -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,
|
||||
}
|
||||
1
sale_exception_portal/models/__init__.py
Normal file
1
sale_exception_portal/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import sale
|
||||
17
sale_exception_portal/models/sale.py
Normal file
17
sale_exception_portal/models/sale.py
Normal file
@@ -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
|
||||
1
sale_exception_portal/tests/__init__.py
Normal file
1
sale_exception_portal/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_check_so_exceptions
|
||||
43
sale_exception_portal/tests/test_check_so_exceptions.py
Normal file
43
sale_exception_portal/tests/test_check_so_exceptions.py
Normal file
@@ -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)
|
||||
75
sale_exception_portal/views/sale_portal_templates.xml
Normal file
75
sale_exception_portal/views/sale_portal_templates.xml
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<template id="sale_order_portal_template_inherit" inherit_id="sale.sale_order_portal_template">
|
||||
<!-- LEFT COLUMN ACTIONS -->
|
||||
<xpath expr="//li[1]" position="replace">
|
||||
<t t-set="sale_order_exceptions" t-value="sale_order._check_sale_order_exceptions()"/>
|
||||
<li class="list-group-item flex-grow-1">
|
||||
<a t-if="sale_order._has_to_be_signed(True) and not sale_order_exceptions"
|
||||
role="button" class="btn btn-primary btn-block mb8"
|
||||
data-toggle="modal"
|
||||
data-target="#modalaccept"
|
||||
href="#">
|
||||
<i class="fa fa-check"/>
|
||||
<t t-if="sale_order._has_to_be_paid(True)"> Sign & Pay</t>
|
||||
<t t-else=""> Accept & Sign</t>
|
||||
</a>
|
||||
<a t-elif="sale_order._has_to_be_paid(True) and not sale_order_exceptions"
|
||||
role="button"
|
||||
id="o_sale_portal_paynow"
|
||||
data-toggle="modal"
|
||||
data-target="#modalaccept"
|
||||
href="#"
|
||||
t-att-class="'btn-block mb8 %s' % ('btn btn-light' if sale_order.transaction_ids else 'btn btn-primary')">
|
||||
<i class="fa fa-check"/>
|
||||
<t t-if="not sale_order.signature">Accept & Pay</t>
|
||||
<t t-else="">Pay Now</t>
|
||||
</a>
|
||||
<t t-if="sale_order_exceptions">
|
||||
<t t-foreach="sale_order_exceptions" t-as="exception">
|
||||
<a href="#discussion" role="button" class="btn btn-danger btn-block mb8"
|
||||
style="max-width: 180px;">
|
||||
<i class="fa fa-warning"/>
|
||||
<span t-esc="exception['description']"/>
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
</li>
|
||||
</xpath>
|
||||
|
||||
<!-- BOTTOM ACTIONS -->
|
||||
<xpath expr="//div[@t-if='sale_order._has_to_be_signed(True) or sale_order._has_to_be_paid(True)']" position="replace">
|
||||
<div t-if="sale_order._has_to_be_signed(True) or sale_order._has_to_be_paid(True)"
|
||||
class="row justify-content-center text-center d-print-none pt-1 pb-4">
|
||||
<t t-set="sale_order_exceptions" t-value="sale_order._check_sale_order_exceptions()"/>
|
||||
<t t-if="sale_order._has_to_be_signed(True)">
|
||||
<div t-if="not sale_order_exceptions" class="col-sm-auto mt8">
|
||||
<a role="button" class="btn btn-primary" data-toggle="modal"
|
||||
data-target="#modalaccept" href="#">
|
||||
<i class="fa fa-check"/>
|
||||
<t t-if="sale_order.has_to_be_paid(True)"> Sign & Pay</t>
|
||||
<t t-else=""> Accept & Sign</t>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-auto mt8">
|
||||
<a role="button" class="btn btn-secondary" href="#discussion">
|
||||
<i class="fa fa-comment"/> Feedback</a>
|
||||
</div>
|
||||
<div class="col-sm-auto mt8">
|
||||
<a role="button" class="btn btn-danger" data-toggle="modal"
|
||||
data-target="#modaldecline" href="#"> <i class="fa fa-times"/> Reject</a>
|
||||
</div>
|
||||
</t>
|
||||
<div t-elif="sale_order._has_to_be_paid(True) and not sale_order_exceptions" class="col-sm-auto mt8">
|
||||
<a role="button" data-toggle="modal" data-target="#modalaccept" href="#"
|
||||
t-att-class="'%s' % ('btn btn-light' if sale_order.transaction_ids else 'btn btn-primary')">
|
||||
<i class="fa fa-check"/> <t t-if="not sale_order.signature">Accept & Pay</t>
|
||||
<t t-else="">Pay Now</t>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
15
sale_exception_portal/views/sale_views.xml
Normal file
15
sale_exception_portal/views/sale_views.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="exception_rule_form_inherit" model="ir.ui.view">
|
||||
<field name="name">exception.rule.form.inherit</field>
|
||||
<field name="model">exception.rule</field>
|
||||
<field name="inherit_id" ref="base_exception.view_exception_rule_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='description']" position="after">
|
||||
<field name="website_description"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
3
sale_exception_user/__init__.py
Normal file
3
sale_exception_user/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import wizard
|
||||
23
sale_exception_user/__manifest__.py
Normal file
23
sale_exception_user/__manifest__.py
Normal file
@@ -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,
|
||||
}
|
||||
3
sale_exception_user/tests/__init__.py
Normal file
3
sale_exception_user/tests/__init__.py
Normal file
@@ -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
|
||||
59
sale_exception_user/tests/test_sale_exception_user.py
Normal file
59
sale_exception_user/tests/test_sale_exception_user.py
Normal file
@@ -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')
|
||||
3
sale_exception_user/wizard/__init__.py
Normal file
3
sale_exception_user/wizard/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import sale_exception_confirm
|
||||
18
sale_exception_user/wizard/sale_exception_confirm.py
Normal file
18
sale_exception_user/wizard/sale_exception_confirm.py
Normal file
@@ -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()
|
||||
18
sale_exception_user/wizard/sale_exception_confirm_view.xml
Normal file
18
sale_exception_user/wizard/sale_exception_confirm_view.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_sale_exception_confirm" model="ir.ui.view">
|
||||
<field name="name">Sale Exceptions User</field>
|
||||
<field name="model">sale.exception.confirm</field>
|
||||
<field name="inherit_id" ref="sale_exception.view_sale_exception_confirm"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='ignore']" position="after">
|
||||
<field name="show_ignore_button" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='action_confirm']" position="after">
|
||||
<button name="action_ignore" string="Ignore" colspan="1" type="object" attrs="{'invisible': [('show_ignore_button', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
0
sale_exception_website/__init__.py
Normal file
0
sale_exception_website/__init__.py
Normal file
22
sale_exception_website/__manifest__.py
Normal file
22
sale_exception_website/__manifest__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
'name': 'Sale Exception Website',
|
||||
'summary': 'Display sale exceptions on eCommerce site',
|
||||
'version': '16.0.1.0.0',
|
||||
'author': "Hibou Corp.",
|
||||
'category': 'Sale',
|
||||
'license': 'AGPL-3',
|
||||
'website': "https://hibou.io",
|
||||
'description': """
|
||||
Display sale exceptions on eCommerce site and prevent purchases
|
||||
""",
|
||||
'depends': [
|
||||
'sale_exception_portal',
|
||||
'website_sale',
|
||||
],
|
||||
'demo': [],
|
||||
'data': [
|
||||
'views/website_templates.xml',
|
||||
],
|
||||
'auto_install': False,
|
||||
'installable': True,
|
||||
}
|
||||
40
sale_exception_website/views/website_templates.xml
Normal file
40
sale_exception_website/views/website_templates.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<template id="payment_inherit" inherit_id="website_sale.payment" name="Payment Exceptions">
|
||||
<!-- Show confirmation page if there are no sale order exceptions -->
|
||||
<xpath expr="//div[@id='wrap']//div[hasclass('oe_cart')]" position="attributes">
|
||||
<attribute name="t-if">not order._check_sale_order_exceptions()</attribute>
|
||||
</xpath>
|
||||
|
||||
<!-- Display sale order exceptions if any are found -->
|
||||
<xpath expr="//div[@id='wrap']//div[hasclass('oe_cart')]" position="after">
|
||||
<t t-if="order._check_sale_order_exceptions()">
|
||||
<t t-set="exceptions" t-value="order._check_sale_order_exceptions()" />
|
||||
<div class="col-12 col-xl order-xl-1">
|
||||
<div class="card bg-danger text-white">
|
||||
<div class="card-body">
|
||||
<t t-foreach="exceptions" t-as="exception">
|
||||
<h4>
|
||||
<i class="fa fa-warning mr-1" />
|
||||
<strong><span t-esc="exception['title']"/></strong>
|
||||
</h4>
|
||||
<p><span t-esc="exception['description']"/></p>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="ml-auto mr-3 mt-2">
|
||||
<a href="/shop/cart" class="float-right btn btn-primary">
|
||||
<span>Back to Cart
|
||||
<span class="fa fa-shopping-cart"/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user