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