diff --git a/product_type_kit/__init__.py b/product_type_kit/__init__.py new file mode 100644 index 00000000000..aee8895e7a3 --- /dev/null +++ b/product_type_kit/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/product_type_kit/__manifest__.py b/product_type_kit/__manifest__.py new file mode 100644 index 00000000000..bc04b060684 --- /dev/null +++ b/product_type_kit/__manifest__.py @@ -0,0 +1,17 @@ +{ + 'name': 'Product Type Kit', + 'version': '1.0', + 'category': 'Sales', + 'license': 'LGPL-3', + 'summary': 'Custom product kit functionality without using BoM', + 'depends': ['sale', 'product'], + 'data': [ + 'security/ir.model.access.csv', + 'views/product_template_views.xml', + 'views/sale_order_views.xml', + 'views/sale_order_line_views.xml', + 'views/kit_subproduct_wizards.xml', + ], + 'installable': True, + 'application': True, +} diff --git a/product_type_kit/models/__init__.py b/product_type_kit/models/__init__.py new file mode 100644 index 00000000000..53fa79af356 --- /dev/null +++ b/product_type_kit/models/__init__.py @@ -0,0 +1,3 @@ +from . import product_template +from . import sale_order +from . import sale_order_line diff --git a/product_type_kit/models/product_template.py b/product_type_kit/models/product_template.py new file mode 100644 index 00000000000..3aeffd94610 --- /dev/null +++ b/product_type_kit/models/product_template.py @@ -0,0 +1,16 @@ +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + is_kit = fields.Boolean(string='Is Kit') + sub_product_ids = fields.Many2many( + 'product.product', + 'product_kit_sub_products_rel', + 'kit_id', + 'sub_product_id', + string='Sub Products', + domain="[('type', '=', 'product')]" + ) + show_subproducts_on_report = fields.Boolean(string='Print Subproducts on Report') diff --git a/product_type_kit/models/sale_order.py b/product_type_kit/models/sale_order.py new file mode 100644 index 00000000000..31b6729e6a6 --- /dev/null +++ b/product_type_kit/models/sale_order.py @@ -0,0 +1,18 @@ +from odoo import api, fields, models + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + print_kit_details = fields.Boolean(string="Print Kit Details") + display_in_report = fields.Boolean(string="Print in report?", default=True) + + @api.model + def unlink(self): + for order in self: + for line in order.order_line: + if not line.is_subproduct: + # delete sub lines linked to this main line + sub_lines = order.order_line.filtered(lambda l: l.kit_parent_line_id == line.id) + sub_lines.unlink() + return super().unlink() diff --git a/product_type_kit/models/sale_order_line.py b/product_type_kit/models/sale_order_line.py new file mode 100644 index 00000000000..a1018d81189 --- /dev/null +++ b/product_type_kit/models/sale_order_line.py @@ -0,0 +1,42 @@ +# models/sale_order_line.py +from odoo import api, fields, models +from odoo.exceptions import UserError + + +class SaleOrder(models.Model): + _inherit = 'sale.order.line' + + kit_parent_line_id = fields.Many2one('sale.order.line', string='Parent Kit Line', ondelete='cascade') + is_kit_product = fields.Boolean( + string="Is Kit Product", compute="_compute_is_kit", store=True + ) + is_subproduct = fields.Boolean(string="Is Sub Product", default=False) + + @api.depends("product_id") + def _compute_is_kit(self): + for line in self: + line.is_kit_product = line.product_id.product_tmpl_id.is_kit + + def write(self, vals): + for line in self: + if line.kit_parent_line_id: + raise UserError("Sub product lines cannot be edited manually.") + return super().write(vals) + + def open_kit_wizard(self): + self.ensure_one() + return { + 'name': f'Configure Kit: {self.product_id.name}', + 'type': 'ir.actions.act_window', + 'res_model': 'kit.sub.product.wizard', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_order_line_id': self.id, + } + } + + @api.onchange('kit_parent_line_id') + def _onchange_disable_edit(self): + if self.kit_parent_line_id: + self.update({'price_unit': 0}) diff --git a/product_type_kit/security/ir.model.access.csv b/product_type_kit/security/ir.model.access.csv new file mode 100644 index 00000000000..ec1e4e8cc81 --- /dev/null +++ b/product_type_kit/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_template,access_product_template,model_product_template,base.group_user,1,1,1,1 +access_sale_order_line,access_sale_order_line,model_sale_order_line,base.group_user,1,1,1,1 +access_sale_order,access_sale_order,model_sale_order,base.group_user,1,1,1,1 +access_kit_sub_product_wizard,access_kit_sub_product_wizard,model_kit_sub_product_wizard,,1,1,1,1 +access_kit_sub_product_line,access_kit_sub_product_line,model_kit_sub_product_line,,1,1,1,1 diff --git a/product_type_kit/views/kit_subproduct_wizards.xml b/product_type_kit/views/kit_subproduct_wizards.xml new file mode 100644 index 00000000000..ba25d6f0d58 --- /dev/null +++ b/product_type_kit/views/kit_subproduct_wizards.xml @@ -0,0 +1,25 @@ + + + + kit.sub.product.wizard + kit.sub.product.wizard + +
+ + + + + + + + + + + +
+
+
+
diff --git a/product_type_kit/views/product_template_views.xml b/product_type_kit/views/product_template_views.xml new file mode 100644 index 00000000000..f2dddce8f68 --- /dev/null +++ b/product_type_kit/views/product_template_views.xml @@ -0,0 +1,14 @@ + + + + product.template.form.kit + product.template + + + + + + + + + diff --git a/product_type_kit/views/sale_order_line_views.xml b/product_type_kit/views/sale_order_line_views.xml new file mode 100644 index 00000000000..73ff97bb4f6 --- /dev/null +++ b/product_type_kit/views/sale_order_line_views.xml @@ -0,0 +1,18 @@ + + + + sale.order.line.tree.readonly.kit + sale.order + + + + 1 + {'readonly': [('is_subproduct', '=', True)]} + + + 1 + {'readonly': [('is_subproduct', '=', True)]} + + + + diff --git a/product_type_kit/views/sale_order_views.xml b/product_type_kit/views/sale_order_views.xml new file mode 100644 index 00000000000..b2a7bd970ac --- /dev/null +++ b/product_type_kit/views/sale_order_views.xml @@ -0,0 +1,16 @@ + + + + sale.order.line.kit.button + sale.order + + + +