Skip to content

Commit 44bdf7d

Browse files
committed
[ADD] sales_products_kit: add functionality to sell products as a kit in Sales
- Added a new "Is Kit" button to the product page for kit selection. - If the product is a kit, sub-products can be selected in the order line. - Introduced a wizard to adjust the quantity and price of sub-products. - On confirmation, sub-products are added to the order line with price set to 0, and costs are moved to the parent product. - Sub-products are automatically deleted if the parent product is removed. - Added a "Print in Report?" boolean to control visibility of sub-products in reports and customer preview page. Task Id :- 5098017
1 parent fbf9ee9 commit 44bdf7d

16 files changed

+320
-0
lines changed

sales_products_kit/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import models
2+
from . import wizard

sales_products_kit/__manifest__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "Sales - Product_Kit",
3+
"version": "1.0",
4+
"description": """
5+
This custom module adds a function to Odoo to sell products as a Kit, but not using a BOM or the Manufacturing Module.
6+
""",
7+
"category": "Sales/Sales",
8+
"depends": ["sale_management"],
9+
"data": [
10+
"security/ir.model.access.csv",
11+
"wizard/sub_product_wizard.xml",
12+
"views/product_view.xml",
13+
"views/sale_order_view.xml",
14+
"report/sale_order_report.xml",
15+
"views/sale_portal_templates.xml",
16+
"report/invoice_report.xml",
17+
],
18+
"installable": True,
19+
"auto_install": False,
20+
"license": "LGPL-3",
21+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from . import product_template
2+
from . import sale_order_line
3+
from . import sale_order
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from odoo import fields, models
2+
3+
4+
class ProductTemplate(models.Model):
5+
_inherit = "product.template"
6+
7+
is_kit = fields.Boolean()
8+
sub_product_ids = fields.Many2many("product.product", string="Sub Product")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from odoo import models, fields
2+
3+
4+
class SaleOrder(models.Model):
5+
_inherit = "sale.order"
6+
7+
print_in_report = fields.Boolean(string="Print in Report ?")
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from odoo import models, fields, api
2+
from odoo.exceptions import UserError
3+
4+
5+
class SaleOrderLine(models.Model):
6+
_inherit = "sale.order.line"
7+
8+
is_kit = fields.Boolean(related="product_template_id.is_kit")
9+
parent_line_id = fields.Many2one("sale.order.line", ondelete="cascade")
10+
11+
@api.ondelete(at_uninstall=False)
12+
def _ondelete_sale_order_line(self):
13+
if not self.parent_line_id:
14+
for line in self:
15+
sub_product_lines = self.env["sale.order.line"].search(
16+
[("parent_line_id", "=", line.id)]
17+
)
18+
sub_product_lines.with_context(allow_child_unlink=True).unlink()
19+
else:
20+
if not self.env.context.get("allow_child_unlink"):
21+
raise UserError(
22+
"You cannot delete a child line directly. Please delete the parent line instead."
23+
)
24+
25+
def write(self, vals):
26+
if "product_uom_qty" in vals and not self.parent_line_id:
27+
for line in self:
28+
sub_product_lines = self.env["sale.order.line"].search(
29+
[("parent_line_id", "=", line.id)]
30+
)
31+
old_qty = line.product_uom_qty
32+
for sub_line in sub_product_lines:
33+
if sub_line:
34+
if old_qty != 0:
35+
qty = sub_line.product_uom_qty / old_qty
36+
new_qty = vals["product_uom_qty"] * qty
37+
sub_line.update({"product_uom_qty": new_qty})
38+
else:
39+
new_qty = vals["product_uom_qty"] * sub_line.product_uom_qty
40+
sub_line.update({"product_uom_qty": new_qty})
41+
return super().write(vals)
42+
43+
def action_subproduct(self):
44+
return {
45+
"type": "ir.actions.act_window",
46+
"name": f"Product: {self.product_id.name}",
47+
"res_model": "sub.product.wizard",
48+
"view_mode": "form",
49+
"target": "new",
50+
"context": {"default_sale_order_line_id": self.id},
51+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
4+
<template id="invoice_document_report_inherited" inherit_id="account.report_invoice_document">
5+
<xpath expr="//tbody/t/tr" position="attributes">
6+
<attribute name="t-if">line.sale_line_ids.order_id.print_in_report or (not line.sale_line_ids.parent_line_id)</attribute>
7+
</xpath>
8+
</template>
9+
10+
</odoo>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
<template id="sale_order_document_report_inherited" inherit_id="sale.report_saleorder_document">
4+
<xpath expr="//tbody/t/tr" position="attributes">
5+
<attribute name="t-if">doc.print_in_report or (not line.parent_line_id)</attribute>
6+
</xpath>
7+
</template>
8+
</odoo>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2+
access_sub_product_wizard,access_sub_product_wizard,model_sub_product_wizard,base.group_user,1,1,1,1
3+
access_sub_product_line,access_sub_product_line,model_sub_product_line,base.group_user,1,1,1,1
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
4+
<record id="product_template_form_view_inherit" model="ir.ui.view">
5+
<field name="name">product.template.form.view.inherit.sales_products_kit</field>
6+
<field name="model">product.template</field>
7+
<field name="inherit_id" ref="sale.product_template_form_view" />
8+
<field name="arch" type="xml">
9+
<xpath expr="//group[@name='group_general']" position="inside">
10+
<field name="is_kit"></field>
11+
<field name="sub_product_ids" widget="many2many_tags" invisible="not is_kit"></field>
12+
</xpath>
13+
</field>
14+
</record>
15+
</odoo>

0 commit comments

Comments
 (0)