Skip to content

Commit f7e46c4

Browse files
committed
[ADD] new_product_type_kit: completed kit product type with wizard & sub-product
- Introduced 'Is Kit' field on product templates to define kit-type products - Added Many2many field to select sub-products for a kit - Added smart button 'Configure Kit' on sale order line, visible only for kit products - Created a wizard to select sub-product quantity and price per main product - Sub-products are auto-added as separate sale order lines under the main kit line - Sub-product lines are read-only & priced at 0 (cost included in main product) - Sub-products support storable/consumable product types for stock tracking - Main product's unit price remains unchanged; subtotal includes sub-product costs - Sub-product lines are auto-deleted if the main kit line is removed - Added 'Print in Report' checkbox on Sale Order to control sub-product visibility - Applied conditional display of sub-products in: - Sale Order PDF - Portal Order Preview - Invoice PDF (QWeb-safe logic using t-set variables)
1 parent 96d8b4a commit f7e46c4

16 files changed

+289
-0
lines changed

new_product_type_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
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
'name': 'Dev Zero Stock Blockage',
3+
'version': '1.0',
4+
'summary': 'Add a new prodcut type kit',
5+
'description': """
6+
Add kit-type products with configurable sub-products and conditional report visibility
7+
""",
8+
'author': 'Raghav Agiwal',
9+
'depends': ['sale_management', 'stock', 'product'],
10+
'data': [
11+
'security/ir.model.access.csv',
12+
'views/product_template_view.xml',
13+
'views/sale_order_line_view.xml',
14+
'views/kit_wizard_views.xml',
15+
'views/portal_saleorder_templates.xml',
16+
'report/report_saleorder_templates.xml',
17+
'report/report_invoice_templates.xml',
18+
],
19+
'installable': True,
20+
'application': True,
21+
'license': 'LGPL-3'
22+
}
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 sale_order_line
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from odoo import fields, models
2+
3+
4+
class ProductTemplate(models.Model):
5+
_inherit = 'product.template'
6+
7+
is_kit = fields.Boolean(string="Is Kit")
8+
sub_product_ids = fields.Many2many(
9+
'product.product',
10+
string="Sub Products",
11+
required=True,
12+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from odoo import fields, models
2+
3+
4+
class SaleOrder(models.Model):
5+
_inherit = 'sale.order'
6+
7+
print_in_report = fields.Boolean(
8+
string="Print in report?",
9+
default=False
10+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from odoo import _, fields, models
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_kit_component = fields.Boolean(string="Is Subproduct")
9+
kit_parent_line_id = fields.Many2one('sale.order.line', string="Kit Parent Line", ondelete="cascade")
10+
kit_unit_cost = fields.Float(string="Unit Price (Wizard)", default=0.0)
11+
12+
def action_open_kit_wizard(self):
13+
return {
14+
'name': 'Kit Components',
15+
'type': 'ir.actions.act_window',
16+
'res_model': 'kit.wizard',
17+
'view_mode': 'form',
18+
'target': 'new',
19+
'context': {
20+
"active_id": self.order_id.id,
21+
'default_product_id': self.product_id.id,
22+
'default_sale_order_line_id': self.id,
23+
}
24+
}
25+
26+
def unlink(self):
27+
# Identify sub-product lines
28+
sub_products = self.filtered(lambda line: line.is_kit_component)
29+
30+
if sub_products and not self.env.context.get('allow_sub_product_deletion'):
31+
if self == sub_products:
32+
raise models.UserError(_("You cannot delete kit sub-products directly. Delete the main kit line instead."))
33+
return (self - sub_products).unlink()
34+
35+
child_lines = self.env['sale.order.line'].search([
36+
('kit_parent_line_id', 'in', self.ids)
37+
])
38+
39+
if child_lines:
40+
child_lines.with_context(allow_sub_product_deletion=True).unlink()
41+
42+
return super().unlink()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
<template id="report_invoice_document_inherit_kit" inherit_id="account.report_invoice_document">
4+
<xpath expr="//table[@name='invoice_line_table']/tbody/t/tr" position="attributes">
5+
<attribute name="t-if">
6+
not any(line.sale_line_ids.mapped('kit_parent_line_id')) or
7+
any(line.sale_line_ids.mapped('kit_parent_line_id') and
8+
line.sale_line_ids.mapped('order_id.print_in_report'))
9+
</attribute>
10+
</xpath>
11+
</template>
12+
</odoo>
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+
<template id="report_saleorder_document_inherit_kit" inherit_id="sale.report_saleorder_document">
4+
<xpath expr="//tbody/t/tr" position="attributes">
5+
<attribute name="t-if">
6+
(not line.kit_parent_line_id) or (doc.print_in_report and line.kit_parent_line_id)
7+
</attribute>
8+
</xpath>
9+
</template>
10+
</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_kit_wizard,access.kit.wizard,model_kit_wizard,,1,1,1,1
3+
access_kit_wizard_line,access.kit.wizard.line,model_kit_wizard_line,,1,1,1,1
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<record id="view_kit_wizard_form" model="ir.ui.view">
4+
<field name="name">kit.wizard.form</field>
5+
<field name="model">kit.wizard</field>
6+
<field name="arch" type="xml">
7+
<form string="Configure Kit" create="0">
8+
<group>
9+
<field name="product_id" readonly="1"/>
10+
</group>
11+
12+
<group string="Sub Products">
13+
<field name="kit_line_ids" nolabel="1">
14+
<list editable="bottom" create="0">
15+
<field name="product_id" readonly="1" force_save="1"/>
16+
<field name="quantity"/>
17+
<field name="price"/>
18+
</list>
19+
</field>
20+
</group>
21+
22+
<footer>
23+
<button string="Confirm" type="object" name="action_confirm" class="btn-primary"/>
24+
<button string="Cancel" class="btn-secondary" special="cancel"/>
25+
</footer>
26+
</form>
27+
</field>
28+
</record>
29+
</odoo>

0 commit comments

Comments
 (0)