@ -0,0 +1,48 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
||||
|
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
Sale Order Multiple Pricelist |
||||
|
============================= |
||||
|
This module helps to apply multiple price lists to the same sale order. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
* Enable "Pricelists" and "Multiple Pricelists" from the Sale Order Configuration Settings. |
||||
|
|
||||
|
Company |
||||
|
======= |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
License |
||||
|
======= |
||||
|
Affero General Public License, v3.0 (AGPL v3). |
||||
|
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
||||
|
|
||||
|
Credits |
||||
|
------- |
||||
|
* Developers: (V17) Bhagyadev KP, |
||||
|
(V18) Aysha Shalin |
||||
|
Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import models |
||||
|
from . import wizard |
@ -0,0 +1,45 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
{ |
||||
|
'name': "Sale Order Multiple Pricelist", |
||||
|
'version': '18.0.1.0.0', |
||||
|
'category': 'Sales', |
||||
|
'summary': 'Multiple price lists can be applied to the same Sale Order.', |
||||
|
'description': """Users can apply different price lists for ech order lines |
||||
|
of the same Sale Order.""", |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'website': 'https://www.cybrosys.com', |
||||
|
'depends': ['sale_management'], |
||||
|
'data': [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/sale_order_views.xml', |
||||
|
'views/res_config_settings_views.xml', |
||||
|
'wizard/pricelist_product_views.xml' |
||||
|
], |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
## Module <multi_pricelist> |
||||
|
|
||||
|
#### 03.01.2025 |
||||
|
#### Version 18.0.1.0.0 |
||||
|
##### ADD |
||||
|
- Initial Commit for Sale Order Multiple Pricelist |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import res_config_settings |
||||
|
from . import sale_order_line |
@ -0,0 +1,51 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class ResConfigSettings(models.TransientModel): |
||||
|
""" This class inherits res.config.settings model to add the settings |
||||
|
for multiple price lists """ |
||||
|
_inherit = 'res.config.settings' |
||||
|
|
||||
|
multi_pricelist = fields.Boolean(string="Multiple Pricelists", |
||||
|
help="Multiple price lists" |
||||
|
"for the same sale order") |
||||
|
|
||||
|
@api.model |
||||
|
def get_values(self): |
||||
|
""" Supering the get_values method to get multi_price list field """ |
||||
|
res = super(ResConfigSettings, self).get_values() |
||||
|
multi_pricelist = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'multi_pricelist.multi_pricelist') |
||||
|
res.update( |
||||
|
multi_pricelist=multi_pricelist, |
||||
|
) |
||||
|
return res |
||||
|
|
||||
|
def set_values(self): |
||||
|
""" Supering the set_values method to set multi_price list field """ |
||||
|
super(ResConfigSettings, self).set_values() |
||||
|
param = self.env['ir.config_parameter'].sudo() |
||||
|
param.set_param('multi_pricelist.multi_pricelist', |
||||
|
self.multi_pricelist) |
@ -0,0 +1,186 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from datetime import datetime |
||||
|
from odoo import fields, models, _ |
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class SaleOrderLine(models.Model): |
||||
|
""" Inherits sale.order.line to add the functions for checking the |
||||
|
visibility of the pricelists in order lines and applying the pricelists |
||||
|
to order lines. """ |
||||
|
_inherit = 'sale.order.line' |
||||
|
|
||||
|
pricelist_visibility = fields.Boolean( |
||||
|
compute="_compute_pricelist_visibility", string="Pricelist Visible", |
||||
|
help="Multi Pricelist enabled or not") |
||||
|
applied_pricelist_id = fields.Many2one( |
||||
|
'product.pricelist', |
||||
|
string="PriceList", |
||||
|
help="Price lists that is applied to the order line.") |
||||
|
|
||||
|
def _get_pricelist_price(self): |
||||
|
""" Overriding the _get_pricelist_price method to apply multiple |
||||
|
pricelists """ |
||||
|
self.ensure_one() |
||||
|
self.product_id.ensure_one() |
||||
|
if self.applied_pricelist_id: |
||||
|
for line in self: |
||||
|
line.pricelist_item_id = line.applied_pricelist_id._get_product_rule( |
||||
|
line.product_id, |
||||
|
quantity=line.product_uom_qty or 1.0, |
||||
|
uom=line.product_uom, |
||||
|
date=line.order_id.date_order, |
||||
|
) |
||||
|
price = self.pricelist_item_id._compute_price( |
||||
|
product=self.product_id.with_context( |
||||
|
**self._get_product_price_context()), |
||||
|
quantity=self.product_uom_qty or 1.0, |
||||
|
uom=self.product_uom, |
||||
|
date=self.order_id.date_order, |
||||
|
currency=self.currency_id, |
||||
|
) |
||||
|
return price |
||||
|
else: |
||||
|
price = self.pricelist_item_id._compute_price( |
||||
|
product=self.product_id.with_context( |
||||
|
**self._get_product_price_context()), |
||||
|
quantity=self.product_uom_qty or 1.0, |
||||
|
uom=self.product_uom, |
||||
|
date=self.order_id.date_order, |
||||
|
currency=self.currency_id, |
||||
|
) |
||||
|
return price |
||||
|
|
||||
|
def apply_pricelist(self): |
||||
|
""" This function will help to select all the pricelists for a product |
||||
|
in order line and apply it""" |
||||
|
for rec in self: |
||||
|
date_time_today = datetime.today().strftime("%Y-%m-%d %H:%M:%S") |
||||
|
# find the matching price list for a product |
||||
|
price_ids = self.env['product.pricelist.item'].search( |
||||
|
['|', '|', ('product_tmpl_id', '=', False), |
||||
|
('categ_id', '=', rec.product_id.categ_id.id), |
||||
|
('product_tmpl_id', '=', rec.product_id.product_tmpl_id.id), |
||||
|
('min_quantity', '<=', rec.product_uom_qty),'|', |
||||
|
('date_start', '<=', date_time_today), |
||||
|
('date_start', '=', False), '|', |
||||
|
('date_end', '>=', date_time_today), |
||||
|
('date_end', '=', False), |
||||
|
]) |
||||
|
variant_ids = self.env['product.pricelist.item'].search( |
||||
|
[ |
||||
|
('product_id', '=', rec.product_id.id), |
||||
|
('min_quantity', '<=', rec.product_uom_qty), |
||||
|
'|', ('date_start', '<=', date_time_today), |
||||
|
('date_start', '=', False), '|', |
||||
|
('date_end', '>=', date_time_today), |
||||
|
('date_end', '=', False), |
||||
|
]) |
||||
|
combined_ids = price_ids + variant_ids |
||||
|
if combined_ids: |
||||
|
pricelist_wizard = self.env['pricelist.product'].create({ |
||||
|
'order_line_id': rec.id, |
||||
|
'line_ids': [(0, 0, { |
||||
|
'pricelist_id': price.pricelist_id.id, |
||||
|
'product_id': rec.product_id.id, |
||||
|
'unit_price': self.unit_price(price), |
||||
|
'unit_cost': rec.product_id.standard_price, |
||||
|
'uom_id': rec.product_id.uom_id.id |
||||
|
}) for price in combined_ids], |
||||
|
}) |
||||
|
else: |
||||
|
raise UserError(_( |
||||
|
"No price list is configured for this product!")) |
||||
|
return { |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'target': 'new', |
||||
|
'name': 'Select Pricelist', |
||||
|
'view_mode': 'form', |
||||
|
'view_id': self.env.ref( |
||||
|
"multi_pricelist.pricelist_wizard_view_form", False).id, |
||||
|
'res_model': 'pricelist.product', |
||||
|
'res_id': pricelist_wizard.id, |
||||
|
} |
||||
|
|
||||
|
def _compute_pricelist_visibility(self): |
||||
|
""" Computes pricelist_visibility by checking the config parameter """ |
||||
|
for rec in self: |
||||
|
rec.pricelist_visibility = self.env[ |
||||
|
'ir.config_parameter'].sudo().get_param( |
||||
|
'multi_pricelist.multi_pricelist') |
||||
|
if rec.order_id.state in ['sale', 'done', 'cancel']: |
||||
|
rec.pricelist_visibility = False |
||||
|
|
||||
|
def unit_price(self, price): |
||||
|
""" Compute the unit price of the product according to the |
||||
|
price_list_item. """ |
||||
|
if price.compute_price == 'fixed': |
||||
|
unt_price = price.fixed_price |
||||
|
elif price.compute_price == 'percentage' and price.percent_price != 0: |
||||
|
unt_price = self.product_id.list_price * ( |
||||
|
1 - price.percent_price / 100) |
||||
|
elif price.compute_price == 'formula' and price.base == 'list_price': |
||||
|
unt_price = (self.product_id.list_price * ( |
||||
|
1 - price.price_discount / 100) + price.price_surcharge) |
||||
|
if price.price_min_margin or price.price_max_margin: |
||||
|
if (unt_price < price.price_min_margin + |
||||
|
self.product_id.list_price): |
||||
|
unt_price = (price.price_min_margin + |
||||
|
self.product_id.list_price) |
||||
|
elif (unt_price > price.price_max_margin + |
||||
|
self.product_id.list_price): |
||||
|
unt_price = (price.price_max_margin + |
||||
|
self.product_id.list_price) |
||||
|
else: |
||||
|
unt_price = unt_price |
||||
|
elif price.compute_price == 'formula' and price.base == 'standard_price': |
||||
|
unt_price = (self.product_id.standard_price * ( |
||||
|
1 - price.price_discount / 100) + price.price_surcharge) |
||||
|
if price.price_min_margin or price.price_max_margin: |
||||
|
if (unt_price < price.price_min_margin + |
||||
|
self.product_id.list_price): |
||||
|
unt_price = (price.price_min_margin + |
||||
|
self.product_id.list_price) |
||||
|
elif (unt_price > price.price_max_margin + |
||||
|
self.product_id.list_price): |
||||
|
unt_price = (price.price_max_margin + |
||||
|
self.product_id.list_price) |
||||
|
else: |
||||
|
unt_price = unt_price |
||||
|
elif price.compute_price == 'formula' and price.base == 'pricelist': |
||||
|
unt_price = (self.unit_price(price.base_pricelist_id.item_ids) * ( |
||||
|
1 - price.price_discount / 100) + price.price_surcharge) |
||||
|
if price.price_min_margin or price.price_max_margin: |
||||
|
if (unt_price < price.price_min_margin + |
||||
|
self.product_id.list_price): |
||||
|
unt_price = (price.price_min_margin + |
||||
|
self.product_id.list_price) |
||||
|
elif (unt_price > price.price_max_margin + |
||||
|
self.product_id.list_price): |
||||
|
unt_price = (price.price_max_margin + |
||||
|
self.product_id.list_price) |
||||
|
else: |
||||
|
unt_price = unt_price |
||||
|
else: |
||||
|
unt_price = self.product_id.list_price |
||||
|
return unt_price |
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 738 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 182 KiB |
After Width: | Height: | Size: 185 KiB |
After Width: | Height: | Size: 208 KiB |
After Width: | Height: | Size: 718 KiB |
After Width: | Height: | Size: 38 KiB |
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<!-- Inherits Configuration settings form view to add the settings to enable multi pricelists --> |
||||
|
<record id="res_config_settings_view_form" |
||||
|
model="ir.ui.view"> |
||||
|
<field name="name">res.config.settings.view.form.inherit.multi.pricelist</field> |
||||
|
<field name="model">res.config.settings</field> |
||||
|
<field name="inherit_id" ref="sale.res_config_settings_view_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//setting[@id='pricelist_configuration']" |
||||
|
position="after"> |
||||
|
<setting id="line_pricelist_settings" invisible="not group_product_pricelist" title="Multiple pricelist for same sale order" help="Multiple pricelist for same sale order"> |
||||
|
<field name="multi_pricelist"/> |
||||
|
</setting> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,21 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<!-- Inherits sale order form view to add the pricelist button to the order lines --> |
||||
|
<record id="view_order_form" model="ir.ui.view"> |
||||
|
<field name="name">sale.order.view.form.inherit.multi.pricelist</field> |
||||
|
<field name="model">sale.order</field> |
||||
|
<field name="inherit_id" ref="sale.view_order_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="/form/sheet/notebook/page/field[@name='order_line']/list/field[@name='price_subtotal']" |
||||
|
position="after"> |
||||
|
<button name="apply_pricelist" type="object" |
||||
|
string="Apply Pricelist" |
||||
|
invisible="not pricelist_visibility"> |
||||
|
<i class="fa fa-fw o_button_icon fa-save"/> |
||||
|
</button> |
||||
|
<field name="applied_pricelist_id" readonly="1"/> |
||||
|
<field name="pricelist_visibility" column_invisible="1"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import pricelist_line |
||||
|
from . import pricelist_product |
@ -0,0 +1,68 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class PricelistLine(models.TransientModel): |
||||
|
""" Model for applying the price lists for sale orderline items """ |
||||
|
_name = 'pricelist.line' |
||||
|
_rec_name = 'wizard_id' |
||||
|
_description = 'Pricelist Lines' |
||||
|
|
||||
|
wizard_id = fields.Many2one('pricelist.product', |
||||
|
string="Price List Selection", |
||||
|
help="Price List Selection") |
||||
|
pricelist_id = fields.Many2one('product.pricelist', |
||||
|
string="PriceList", |
||||
|
help="Price lists that can be applied for " |
||||
|
"the order line.") |
||||
|
product_id = fields.Many2one('product.product', |
||||
|
string="Product", |
||||
|
help="Order line Product") |
||||
|
unit_price = fields.Float(string="Unit Price", |
||||
|
help="Price of the product per unit") |
||||
|
unit_cost = fields.Float(string='Unit Cost', |
||||
|
help="Cost of the product per unit") |
||||
|
margin = fields.Float(compute='_compute_margin', string="Margin %", |
||||
|
help="calculated by ((unit price - unit cost) " |
||||
|
"unit cost)* 100") |
||||
|
uom_id = fields.Many2one('uom.uom', string="UOM", help="Unit Of Measure") |
||||
|
|
||||
|
@api.depends('unit_price', 'unit_cost') |
||||
|
def _compute_margin(self): |
||||
|
""" This function will compute the margin for the product when the |
||||
|
price list applied. |
||||
|
It is calculated by ((unit price - unit cost)/ unit cost)* 100 """ |
||||
|
for rec in self: |
||||
|
rec.margin = 100 |
||||
|
if rec.unit_cost: |
||||
|
rec.margin = ((rec.unit_price-rec.unit_cost)/rec.unit_cost)*100 |
||||
|
|
||||
|
def apply_pricelist(self): |
||||
|
"""This function will apply the selected pricelist to the order line""" |
||||
|
for rec in self: |
||||
|
rec.wizard_id.order_line_id.update({ |
||||
|
'applied_pricelist_id': rec.pricelist_id, |
||||
|
}) |
||||
|
rec.wizard_id.order_line_id.update({ |
||||
|
'price_unit': rec.unit_price, |
||||
|
}) |
@ -0,0 +1,35 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Aysha Shalin (odoo@cybrosys.com) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC |
||||
|
# LICENSE (AGPL v3) along with this program. |
||||
|
# If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class PricelistProduct(models.TransientModel): |
||||
|
""" New transient model for the price list wizard """ |
||||
|
_name = 'pricelist.product' |
||||
|
_rec_name = 'order_line_id' |
||||
|
_description = 'Price list product' |
||||
|
|
||||
|
order_line_id = fields.Many2one('sale.order.line', |
||||
|
string="Order Line", |
||||
|
help="Order line of the selected order") |
||||
|
line_ids = fields.One2many('pricelist.line', 'wizard_id', |
||||
|
string="Price lists", help="Pricelist lines") |
@ -0,0 +1,38 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<!-- Pricelist wizard form view --> |
||||
|
<record id="pricelist_wizard_view_form" model="ir.ui.view"> |
||||
|
<field name="name">pricelist.product.view.form</field> |
||||
|
<field name="model">pricelist.product</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<sheet> |
||||
|
<h3> |
||||
|
Select one Pricelist |
||||
|
</h3> |
||||
|
<notebook> |
||||
|
<page string="Pricelists"> |
||||
|
<field name="line_ids"> |
||||
|
<list> |
||||
|
<field name="pricelist_id"/> |
||||
|
<field name="product_id"/> |
||||
|
<field name="unit_price"/> |
||||
|
<field name="margin"/> |
||||
|
<field name="uom_id"/> |
||||
|
<button name="apply_pricelist" |
||||
|
string="Apply" type="object" |
||||
|
class="btn-primary" |
||||
|
data-hotkey="q"/> |
||||
|
</list> |
||||
|
</field> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
<footer> |
||||
|
<button string="Cancel" special="cancel" |
||||
|
data-hotkey="z"/> |
||||
|
</footer> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |