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:
Cedric Collins
2023-11-02 22:31:58 +00:00
18 changed files with 364 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import models

View 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,
}

View File

@@ -0,0 +1 @@
from . import sale

View 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

View File

@@ -0,0 +1 @@
from . import test_check_so_exceptions

View 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)

View 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 &amp; Pay</t>
<t t-else=""> Accept &amp; 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 &amp; 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 &amp; Pay</t>
<t t-else=""> Accept &amp; 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 &amp; Pay</t>
<t t-else="">Pay Now</t>
</a>
</div>
</div>
</xpath>
</template>
</odoo>

View 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>

View File

@@ -0,0 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import wizard

View 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,
}

View 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

View 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')

View 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

View 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()

View 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>

View File

View 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,
}

View 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>