Skip to content

product_kit: Add option to set as kit #710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: 18.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions product_kit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
21 changes: 21 additions & 0 deletions product_kit/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
'name': "Product As Kit",
'version': '1.0',
'depends': ['stock', 'sale_management'],
'author': "Rishav Shah",
'category': 'product',
'description': """
Add new new product type as kit
""",
'installable': True,
'application': True,
'license': 'LGPL-3',
'data': [
'security/ir.model.access.csv',
'views/product_views.xml',
'views/sale_order_views.xml',
'views/kit_products_wizard_views.xml',
'views/sale_order_report.xml',
'views/invoice_report.xml',
],
}
4 changes: 4 additions & 0 deletions product_kit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import product_template
from . import sale_order_line
from . import sale_order
from . import kit_products_wizard
105 changes: 105 additions & 0 deletions product_kit/models/kit_products_wizard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from odoo import models, fields, api


class KitProductsWizardLine(models.TransientModel):
_name = "kit.products.wizard.line"
_description = "Kit Products Wizard Line"

wizard_line_id = fields.Many2one("kit.products.wizard", required=True)
product_id = fields.Many2one("product.product", string="Product")
product_quantity = fields.Float(string="Quantity")
price = fields.Float(string="Unit Price")


class KitProductsWizard(models.TransientModel):
_name = "kit.products.wizard"
_description = "Kit Products Wizard"

sale_order_id = fields.Many2one("sale.order", string="Sale Order", readonly=True)
product_template_id = fields.Many2one("product.template", string="Product", readonly=True)
subProduct_ids = fields.One2many("kit.products.wizard.line", "wizard_line_id", string="Sub Products")

@api.model
def default_get(self, fields_list):
res = super().default_get(fields_list)
sale_order_id = self.env.context.get("default_sale_order_id")
product_template_id = self.env.context.get("default_product_template_id")

res.update({
"sale_order_id": sale_order_id,
"product_template_id": product_template_id,
})

if sale_order_id and product_template_id:
product_template = self.env["product.template"].browse(product_template_id)
sub_products = product_template.subProduct_ids

existing_lines = self.env["sale.order.line"].search([
("order_id", "=", sale_order_id),
("product_id", "in", sub_products.ids)
])

line_data = []
for sub_product in sub_products:
existing_line = existing_lines.filtered(lambda l: l.product_id.id == sub_product.id)
line_data.append((0, 0, {
"product_id": sub_product.id,
"product_quantity": existing_line.product_uom_qty if existing_line else 1,
"price": existing_line.last_updated_price if existing_line else sub_product.list_price,
}))

res["subProduct_ids"] = line_data

return res

def action_open_wizard_popup(self):
self.ensure_one()

so_line_model = self.env["sale.order.line"]
total_price = 0.0

for sub in self.subProduct_ids:
sub_total = sub.product_quantity * sub.price
total_price += sub_total

line_vals = {
"product_uom_qty": sub.product_quantity,
"price_unit": 0.0,
"last_updated_price": sub.price,
}

existing_line = so_line_model.search([
("order_id", "=", self.sale_order_id.id),
("product_id", "=", sub.product_id.id),
("is_subProduct", "=", True),
], limit=1)

if existing_line:
existing_line.write(line_vals)
else:
line_vals.update({
"name": sub.product_id.name,
"order_id": self.sale_order_id.id,
"product_id": sub.product_id.id,
"is_subProduct": True,
})
so_line_model.create(line_vals)

main_product = self.product_template_id.product_variant_id
main_line = so_line_model.search([
("order_id", "=", self.sale_order_id.id),
("product_id", "=", main_product.id),
], limit=1)

if main_line:
main_line.price_unit = total_price * main_line.product_uom_qty
else:
so_line_model.create({
"order_id": self.sale_order_id.id,
"product_id": main_product.id,
"product_uom_qty": 1,
"price_unit": total_price,
"name": self.product_template_id.name,
})

return {"type": "ir.actions.act_window_close"}
16 changes: 16 additions & 0 deletions product_kit/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from odoo import api, fields, models


class ProductTemplate(models.Model):
_inherit = 'product.template'

isKit = fields.Boolean(string="is Kit", default=False)
subProduct_ids = fields.Many2many('product.product', string="Sub Products")
subProductVisibility = fields.Boolean(string="is Kit", default=False, compute='_compute_sub_product_visiblity')

@api.depends_context('isKit')
def _compute_sub_product_visiblity(self):
if self.isKit:
self.subProductVisibility = True
else:
self.subProductVisibility = False
7 changes: 7 additions & 0 deletions product_kit/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from odoo import models, fields


class SaleOrder(models.Model):
_inherit = "sale.order"

is_kit_printable = fields.Boolean(string="Print in report ?", default=True)
36 changes: 36 additions & 0 deletions product_kit/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from odoo import models, fields


class SaleOrderLine(models.Model):
_inherit = "sale.order.line"

isKit = fields.Boolean(related="product_template_id.isKit", store=True)
is_subProduct = fields.Boolean(string="Created from Wizard", default=False)
last_updated_price = fields.Float("Kit Price", help="Custom price stored for use in kit wizard")

def action_open_kit_wizard(self):
return {
"name": "Kit Products",
"type": "ir.actions.act_window",
"res_model": "kit.products.wizard",
"view_mode": "form",
"target": "new",
"context": {
"default_sale_order_id": self.order_id.id,
"default_product_template_id": self.product_template_id.id,
}
}

def unlink(self):
"""When main product line is deleted, all the related wizard-generated sale order lines are deleted."""
main_product_line = self.filtered(lambda line: not line.is_subProduct)

for sub_product_lines in main_product_line:
kit_lines = self.search([
("order_id", "=", sub_product_lines.order_id.id),
("is_subProduct", "=", True),
("product_id", "in", sub_product_lines.product_id.subProduct_ids.ids),
])
kit_lines.unlink()

return super().unlink()
3 changes: 3 additions & 0 deletions product_kit/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
product_kit.access_kit_products_wizard_line,access_kit_products_wizard_line,product_kit.model_kit_products_wizard_line,base.group_user,1,1,1,1
product_kit.access_kit_products_wizard,access_kit_products_wizard,product_kit.model_kit_products_wizard,base.group_user,1,1,1,1
10 changes: 10 additions & 0 deletions product_kit/views/invoice_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<odoo>
<template id="report_invoice_document_subproduct" inherit_id="account.report_invoice_document">
<xpath expr="//tbody[hasclass('invoice_tbody')]//tr" position="attributes">
<attribute name="t-if">
(line.sale_line_ids.order_id.is_kit_printable) or (not line.sale_line_ids.filtered('is_subProduct'))
</attribute>
</xpath>
</template>
</odoo>
39 changes: 39 additions & 0 deletions product_kit/views/kit_products_wizard_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="action_kit_products_wizard" model="ir.actions.act_window">
<field name="name">Kit Product</field>
<field name="res_model">kit.products.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="view_kit_products_wizard" model="ir.ui.view">
<field name="name">view_kit_products_wizard</field>
<field name="model">kit.products.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<h1>PRODUCT </h1>
<h1><field name="product_template_id"/></h1>
</group>
<group>
<h2>SubProducts</h2>
</group>
<group>
<field name="subProduct_ids" nolabel="1">
<list editable="bottom">
<field name="product_id"/>
<field name="product_quantity"/>
<field name="price"/>
</list>
</field>
</group>
<footer>
<button name="action_open_wizard_popup" type="object" string="Confirm" class="btn-primary"/>
<button string="Close" class="oe_secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
</odoo>
14 changes: 14 additions & 0 deletions product_kit/views/product_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="product_template_form_view_inherit" model="ir.ui.view">
<field name="name">product.template.form.view.inherit</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='general_information']/group/group[@name='group_general']" position="inside">
<field name="isKit" string="Is Kit"/>
<field name="subProduct_ids" widget="many2many_tags" string="Sub Products" invisible="not subProductVisibility"/>
</xpath>
</field>
</record>
</odoo>
17 changes: 17 additions & 0 deletions product_kit/views/sale_order_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_saleorder_document_inherit" inherit_id="sale.sale_order_portal_content">
<xpath expr="//table[@id='sales_order_table']//tbody[@class='sale_tbody']//t[@t-foreach='lines_to_report']" position="attributes">
<attribute name="t-if">
(not line.is_subProduct) or (sale_order.is_kit_printable and line.is_subProduct)
</attribute>
</xpath>
</template>
<template id="report_saleorder_document" inherit_id="sale.report_saleorder_document">
<xpath expr="//tbody/t[@t-foreach='lines_to_report']" position="attributes">
<attribute name="t-if">
not line.is_subProduct or doc.is_kit_printable
</attribute>
</xpath>
</template>
</odoo>
26 changes: 26 additions & 0 deletions product_kit/views/sale_order_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form.view.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='payment_term_id']" position="after">
<field name="is_kit_printable"/>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_template_id']" position="after">
<button name="action_open_kit_wizard" type="object" string="Show Sub Products" class="oe_highlight"
invisible = "not isKit"/>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_template_id']" position="attributes">
<attribute name="readonly">is_subProduct</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_uom_qty']" position="attributes">
<attribute name="readonly">is_subProduct</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='price_unit']" position="attributes">
<attribute name="readonly">is_subProduct</attribute>
</xpath>
</field>
</record>
</odoo>