Skip to content

Commit 766b048

Browse files
committed
[ADD] kit_product_type: implement kit type product and sale order management
- Introduced a new product type Kit via is_kit Boolean field on product.template. - When is_kit is enabled, a Many2many field appears to select sub-products. - On Sales Orders, kit products now show a Add Sub Products button. - Sub-products can be customized (quantity and price) through a wizard. - Confirming the wizard adds sub-products to the order line with unit price and subtotal as 0. - The cost of sub-products is included in the main kit product’s subtotal. - Added `print_in_report` Boolean on sale.order to control printing sub-products in reports/customer preview. - Once the Sales Order is confirmed, the Add Sub Products button is hidden.
1 parent f1a643e commit 766b048

13 files changed

+300
-0
lines changed

kit_product_type/__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

kit_product_type/__manifest__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "kit_product_type",
3+
"depends": ["base", "product", "sale", "sale_management"],
4+
"data": [
5+
"views/product_template_view.xml",
6+
"views/sale_order_view.xml",
7+
"wizard/sale_order_line_wizard.xml",
8+
"security/ir.model.access.csv",
9+
],
10+
"license": "LGPL-3",
11+
}
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
3+
from . import sales_order_line
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from odoo import models, fields
2+
3+
4+
class ProductTemplate(models.Model):
5+
_inherit = "product.template"
6+
7+
is_kit = fields.Boolean(string="Is Kit?", default=False)
8+
sub_products = fields.Many2many("product.product", string="Sub Products")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from odoo import fields, models
2+
3+
4+
class SaleOrder(models.Model):
5+
_inherit = "sale.order"
6+
7+
print_in_report = fields.Boolean(string="Print in Report?")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from odoo import api, models, fields
2+
3+
4+
class SaleOrderLine(models.Model):
5+
_inherit = "sale.order.line"
6+
7+
is_kit = fields.Boolean(related="product_template_id.is_kit")
8+
is_sub_product_ol = fields.Boolean(default=False)
9+
wizard_price = fields.Float()
10+
main_order_line_id = fields.Many2one(
11+
"sale.order.line",
12+
string="Parent Line",
13+
ondelete="cascade",
14+
)
15+
16+
child_line_ids = fields.One2many(
17+
"sale.order.line",
18+
"main_order_line_id",
19+
string="Child Lines",
20+
)
21+
display_price = fields.Float(
22+
compute="_compute_display_price", inverse="_compute_unit_price"
23+
)
24+
display_sub_total = fields.Float(compute="_compute_amount_price")
25+
26+
@api.depends("price_unit", "is_sub_product_ol")
27+
def _compute_display_price(self):
28+
for line in self:
29+
line.display_price = 0.0 if line.is_sub_product_ol else line.price_unit
30+
31+
@api.depends("display_price", "price_subtotal", "is_sub_product_ol")
32+
def _compute_amount_price(self):
33+
for line in self:
34+
line.display_sub_total = (
35+
0.0 if line.is_sub_product_ol else line.price_subtotal
36+
)
37+
38+
def _compute_unit_price(self):
39+
for line in self:
40+
line.price_unit = line.display_price
41+
42+
def unlink(self):
43+
for line in self:
44+
line.main_order_line_id.price_subtotal -= (
45+
line.product_uom_qty * line.wizard_price
46+
)
47+
48+
return super().unlink()
49+
50+
def open_sub_product_wizard(self):
51+
return {
52+
"name": "Sub Products Wizard",
53+
"type": "ir.actions.act_window",
54+
"res_model": "sale.order.line.wizard",
55+
"view_mode": "form",
56+
"target": "new",
57+
"context": {"active_id": self.id},
58+
}
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_sale_order_line_wizard,sale.order.line.wizard,model_sale_order_line_wizard,base.group_user,1,1,1,0
3+
access_sale_order_line_wizard_line,sale.order.line.wizard.line,model_sale_order_line_wizard_line,base.group_user,1,1,1,0
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0"?>
2+
<odoo>
3+
<record id="product_template_kit_inherit_view" model="ir.ui.view">
4+
<field name="name">product.template.inherit.view</field>
5+
<field name="model">product.template</field>
6+
<field name="inherit_id" ref="product.product_template_only_form_view"/>
7+
<field name="arch" type="xml">
8+
<xpath expr="//page[@name='general_information']//group[@name='group_general']" position="inside">
9+
<field name="is_kit"/>
10+
<field name="sub_products" widget="many2many_tags" invisible="not is_kit"/>
11+
</xpath>
12+
</field>
13+
</record>
14+
<template id="preview_saleorder_custom" inherit_id="sale.sale_order_portal_content">
15+
<xpath expr="//t[@t-foreach='lines_to_report']/tr" position="attributes">
16+
<attribute name="t-att-class">'d-none' if (not sale_order.print_in_report and line.is_sub_product_ol) else ''+
17+
('fw-bold o_line_section' if (line.display_type == 'line_section' or line.product_type == 'combo')
18+
else 'fst-italic o_line_note' if line.display_type == 'line_note' else '')</attribute>
19+
</xpath>
20+
</template>
21+
<template id="report_saleorder_custom" inherit_id="sale.report_saleorder_document">
22+
<xpath expr="//t[@t-foreach='lines_to_report']/tr" position="attributes">
23+
<attribute name="t-att-class">'d-none' if (not doc.print_in_report and line.is_sub_product_ol) else ''</attribute>
24+
</xpath>
25+
</template>
26+
</odoo>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0"?>
2+
<odoo>
3+
<record id="sale_order_inherit_view_form" model="ir.ui.view">
4+
<field name="name">Sale.Order.Inherit.View.Form</field>
5+
<field name="model">sale.order</field>
6+
<field name="inherit_id" ref="sale.view_order_form"/>
7+
<field name="arch" type="xml">
8+
<xpath expr="//sheet//group[@name='sale_header']//group[@name='order_details']" position="inside">
9+
<field name="print_in_report"/>
10+
</xpath>
11+
<xpath expr="//field[@name='product_template_id']" position="after">
12+
<button name='open_sub_product_wizard' type="object" string="Add Sub-Product" invisible="not is_kit or state=='sale'"/>
13+
</xpath>
14+
<xpath expr="//field[@name='order_line']//list//field[@name='product_template_id']" position="attributes">
15+
<attribute name="readonly">is_sub_product_ol</attribute>
16+
</xpath>
17+
<xpath expr="//field[@name='order_line']//list//field[@name='product_uom_qty']" position="attributes">
18+
<attribute name="readonly">is_sub_product_ol</attribute>
19+
</xpath>
20+
<xpath expr="//field[@name='order_line']//list//field[@name='price_unit']" position="attributes">
21+
<attribute name="readonly">is_sub_product_ol</attribute>
22+
<attribute name="column_invisible">True</attribute>
23+
</xpath>
24+
<xpath expr="//field[@name='order_line']//list//field[@name='price_unit']" position="after">
25+
<field name="display_price" string="Unit Price"/>
26+
</xpath>
27+
<xpath expr="//field[@name='order_line']//list//field[@name='display_price']" position="attributes">
28+
<attribute name="readonly">is_sub_product_ol</attribute>
29+
</xpath>
30+
<xpath expr="//field[@name='order_line']//list//field[@name='price_subtotal']" position="after">
31+
<field name="display_sub_total" string="Amount"/>
32+
</xpath>
33+
<xpath expr="//field[@name='order_line']//list//field[@name='price_subtotal']" position="attributes">
34+
<attribute name="column_invisible">True</attribute>
35+
</xpath>
36+
</field>
37+
</record>
38+
</odoo>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import sale_order_line_wizard
2+
from . import sale_order_line_wizard_lines

0 commit comments

Comments
 (0)