product_pricelist_supplierinfo_chatter
This commit is contained in:
parent
02eff1880f
commit
5137d23562
7 changed files with 293 additions and 0 deletions
3
product_pricelist_supplierinfo_chatter/__init__.py
Normal file
3
product_pricelist_supplierinfo_chatter/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
32
product_pricelist_supplierinfo_chatter/__manifest__.py
Executable file
32
product_pricelist_supplierinfo_chatter/__manifest__.py
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
{
|
||||
"name": "Product Pricelist Supplierinfo Chatter",
|
||||
"version": "18.0.3.0.0",
|
||||
"license": "AGPL-3",
|
||||
"author": "Bemade",
|
||||
"category": "Tools",
|
||||
"depends": [
|
||||
"base",
|
||||
"product",
|
||||
"stock",
|
||||
"product_pricelist_supplierinfo",
|
||||
"sale",
|
||||
"purchase",
|
||||
"mrp",
|
||||
],
|
||||
"description": """
|
||||
This module extends basic inventory and pricelist management in
|
||||
Odoo to include support for supplierinfo chatter making price
|
||||
updates visible in the chatter.
|
||||
""",
|
||||
"demo": [],
|
||||
'data': [
|
||||
'views/product_view.xml',
|
||||
'views/supplierinfo_pricelist.xml',
|
||||
],
|
||||
'test': [],
|
||||
'installable': True,
|
||||
'active': False
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -0,0 +1 @@
|
|||
from . import product_supplier_info
|
||||
146
product_pricelist_supplierinfo_chatter/models/product_supplier_info.py
Executable file
146
product_pricelist_supplierinfo_chatter/models/product_supplier_info.py
Executable file
|
|
@ -0,0 +1,146 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from markupsafe import Markup
|
||||
|
||||
|
||||
class ProductSupplierInfo(models.Model):
|
||||
_name = "product.supplierinfo"
|
||||
_inherit = ["product.supplierinfo", "mail.thread", "mail.activity.mixin"]
|
||||
|
||||
# Commented out because breaking basic Odoo tests. See if this is really needed.
|
||||
|
||||
# _sql_constraints = [("supplierinfo_product_tmpl_id_no_null",
|
||||
# "CHECK((product_tmpl_id IS NOT NULL))",
|
||||
# "Supplier pricelist need product template"),
|
||||
# ]
|
||||
|
||||
# This while avoid the database to save those record with lost product_tmpl_id
|
||||
@api.depends("supplier_list_price", "supplier_discount_percent")
|
||||
def _compute_price(self):
|
||||
for rec in self:
|
||||
rec.price = rec.supplier_list_price - (
|
||||
rec.supplier_list_price * rec.supplier_discount_percent / 100
|
||||
)
|
||||
|
||||
@api.depends("supplier_discount_percent")
|
||||
def _inverse_price(self):
|
||||
for rec in self:
|
||||
discount = (
|
||||
rec.supplier_discount_percent if rec.supplier_discount_percent else 0
|
||||
)
|
||||
rec.supplier_list_price = (100 * rec.price) / (100 - discount)
|
||||
|
||||
# We add tracking to the fields that are displayed in the chatter
|
||||
partner_id = fields.Many2one(
|
||||
tracking=True,
|
||||
domain=[("is_company", "=", True)]
|
||||
)
|
||||
|
||||
product_name = fields.Char(tracking=True)
|
||||
product_code = fields.Char(tracking=True)
|
||||
product_uom = fields.Many2one(tracking=True)
|
||||
min_qty = fields.Float(tracking=True)
|
||||
currency_id = fields.Many2one(tracking=True)
|
||||
date_start = fields.Date(tracking=True)
|
||||
date_end = fields.Date(tracking=True)
|
||||
product_id = fields.Many2one(tracking=True)
|
||||
product_tmpl_id = fields.Many2one(tracking=True)
|
||||
delay = fields.Integer(tracking=True)
|
||||
|
||||
date_updated = fields.Date(
|
||||
string="Last updated",
|
||||
help="Date at which the supplier " + " list price was last updated.",
|
||||
)
|
||||
|
||||
purchasing_notes = fields.Text(
|
||||
tracking=True,
|
||||
string="Purchasing Notes"
|
||||
)
|
||||
|
||||
supplier_list_price = fields.Float(
|
||||
string="Supplier List Price",
|
||||
digits="Product Price",
|
||||
tracking=True,
|
||||
help="""This the supplier list price to which supplier discounts are applied, if
|
||||
any, and the net price if no supplier discounts are to be applied""",
|
||||
)
|
||||
|
||||
supplier_discount_percent = fields.Float(
|
||||
string="Supplier discount (%)",
|
||||
digits="Product Price",
|
||||
tracking=True,
|
||||
default=0
|
||||
)
|
||||
|
||||
price = fields.Float(
|
||||
compute="_compute_price",
|
||||
inverse="_inverse_price",
|
||||
string="Supplier Price",
|
||||
digits="Product Price",
|
||||
help="This price will be considered as a price for the supplier UoM if any or "
|
||||
"the default Unit of Measure of the product otherwise",
|
||||
store=True,
|
||||
)
|
||||
|
||||
def _generate_chatter(self, vals, operation):
|
||||
if len(self) == 1 and self.product_tmpl_id:
|
||||
msg = ""
|
||||
headmsg = (
|
||||
f"<a href='#' data-oe-model='product.supplierinfo' data-oe-id='{self.id}'>"
|
||||
f"Price {operation} for {self.product_id.name} : <br /></a>"
|
||||
)
|
||||
if self.min_qty > 0:
|
||||
msg += f"<li>Minimum qty : {self.min_qty}</li>"
|
||||
if self.date_start:
|
||||
msg += f"<li>Starting : {self.date_start}</li>"
|
||||
if self.date_end:
|
||||
msg += f"<li>Ending : {self.date_end}</li>"
|
||||
if msg:
|
||||
msg = headmsg + "<ul>" + msg + "</ul>"
|
||||
else:
|
||||
msg = headmsg
|
||||
for change in vals:
|
||||
msg += f"{change} --> {vals[change]}<br />"
|
||||
# Should always be there
|
||||
if self.product_tmpl_id:
|
||||
self.product_tmpl_id.message_post(
|
||||
body=Markup(msg),
|
||||
)
|
||||
# only for variant
|
||||
if self.product_id:
|
||||
self.product_id.message_post(body=Markup(msg))
|
||||
|
||||
# Well hard time to set the chatter
|
||||
# def create(self, vals):
|
||||
# res = super(ProductSupplierInfo, self).create(vals)
|
||||
# # # res._generate_chatter(vals, 'create')
|
||||
|
||||
def write(self, vals):
|
||||
res = super(ProductSupplierInfo, self).write(vals)
|
||||
self._generate_chatter(vals, "modify")
|
||||
return res
|
||||
|
||||
def suplierinfo_show_details(self):
|
||||
"""
|
||||
Action to open product.supplierinfo (pricelist) in its own windows and not in a javascript
|
||||
popup to avoid loosing product_tmpl_id. We rely on both context and domain to pass the
|
||||
information
|
||||
"""
|
||||
# views = [(self.env.ref('account.invoice_supplier_tree').id, 'tree'),
|
||||
# (self.env.ref('account.invoice_supplier_form').id, 'form')]
|
||||
return {
|
||||
"name": "Supplier price",
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"res_id": self.id,
|
||||
"context": self.env.context,
|
||||
"res_model": "product.supplierinfo",
|
||||
"domain": [
|
||||
("product_tmpl_id", "=", self.product_tmpl_id),
|
||||
("product_id", "=", self.product_id),
|
||||
],
|
||||
"type": "ir.actions.act_window",
|
||||
# 'view_id': False,
|
||||
# 'views': views,
|
||||
}
|
||||
BIN
product_pricelist_supplierinfo_chatter/static/description/icon.png
Executable file
BIN
product_pricelist_supplierinfo_chatter/static/description/icon.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
36
product_pricelist_supplierinfo_chatter/views/product_view.xml
Executable file
36
product_pricelist_supplierinfo_chatter/views/product_view.xml
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Vue de liste personnalisée pour supplier info sans édition en ligne -->
|
||||
<record id="product_supplierinfo_tree_view_no_edit" model="ir.ui.view">
|
||||
<field name="name">product.supplierinfo.tree.no.edit</field>
|
||||
<field name="model">product.supplierinfo</field>
|
||||
<field name="inherit_id" ref="purchase.product_supplierinfo_tree_view2" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//list" position="attributes">
|
||||
<!-- Supprimer l'attribut editable pour forcer l'ouverture du formulaire -->
|
||||
<attribute name="editable"></attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Modification de la vue produit pour utiliser notre vue personnalisée -->
|
||||
<record id="product_template_only_form_view_landed" model="ir.ui.view">
|
||||
<field name="name">product.template.form.view.landed</field>
|
||||
<field name="inherit_id" ref="purchase.view_product_supplier_inherit" />
|
||||
<field name="model">product.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Modifier le contexte pour utiliser notre vue sans édition -->
|
||||
<field name="seller_ids" position="attributes">
|
||||
<attribute name="context">
|
||||
{'default_product_tmpl_id': id,
|
||||
'product_template_invisible_variant': True,
|
||||
'list_view_ref':'product_pricelist_supplierinfo_chatter.product_supplierinfo_tree_view_no_edit'}</attribute>
|
||||
</field>
|
||||
<field name="variant_seller_ids" position="attributes">
|
||||
<attribute name="context">
|
||||
{'model': 'product.template', 'active_id': id,
|
||||
'list_view_ref':'product_pricelist_supplierinfo_chatter.product_supplierinfo_tree_view_no_edit'}</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="product_supplierinfo_form_view_chatter" model="ir.ui.view">
|
||||
<field name="name">supplierinfo.pricelist.chatter</field>
|
||||
<field name="model">product.supplierinfo</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Vendor Information">
|
||||
<sheet>
|
||||
<group>
|
||||
<group name="vendor" string="Vendor">
|
||||
<field name="product_variant_count" invisible="1" />
|
||||
<field name="partner_id"
|
||||
context="{'res_partner_search_mode': 'supplier'}" />
|
||||
<field name="product_name" />
|
||||
<field name="product_code" />
|
||||
<label for="delay" />
|
||||
<div>
|
||||
<field name="delay" class="oe_inline" /> days </div>
|
||||
</group>
|
||||
|
||||
<group string="Pricelist">
|
||||
<field name="product_tmpl_id" string="Product"
|
||||
invisible="context.get('visible_product_tmpl_id', True)" />
|
||||
<field name="product_id" groups="product.group_product_variant"
|
||||
options="{'no_create': True}" />
|
||||
<label for="min_qty" />
|
||||
<div class="o_row">
|
||||
<field name="min_qty" />
|
||||
<field name="product_uom" groups="uom.group_uom"
|
||||
options="{'no_open': True}" />
|
||||
</div>
|
||||
<label for="price" string="Unit Price" />
|
||||
<div class="o_row">
|
||||
<field name="price" class="oe_inline" widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}" />
|
||||
<field name="currency_id" groups="base.group_multi_currency"
|
||||
options="{'no_open': True}" />
|
||||
</div>
|
||||
<label for="date_start" string="Validity" />
|
||||
<div class="o_row">
|
||||
<field name="date_start" class="oe_inline" /> to <field
|
||||
name="date_end" class="oe_inline" />
|
||||
</div>
|
||||
<field name="discount" />
|
||||
<field name="company_id" options="{'no_create': True}" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Section personnalisée pour les informations fournisseur -->
|
||||
<group>
|
||||
<group string="Supplier Pricing" col="2">
|
||||
<field name="supplier_list_price" widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}" />
|
||||
<field name="supplier_discount_percent" widget="percentage" />
|
||||
</group>
|
||||
|
||||
<group string="Notes" col="1">
|
||||
<field name="purchasing_notes" nolabel="1"
|
||||
placeholder="Add purchasing notes, terms, conditions, or special instructions..." />
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
<!-- Chatter pour la traçabilité -->
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" groups="base.group_user" />
|
||||
<field name="activity_ids" />
|
||||
<field name="message_ids" />
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in a new issue