Skip to content

[ADD] Product Kit: New Product Type #703

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

Draft
wants to merge 1 commit into
base: 18.0
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions product_kit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import wizard
15 changes: 15 additions & 0 deletions product_kit/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
'name': 'Product Kit',
'Category': 'Sales/Product Kit',
'license': 'LGPL-3',
'installable': True,
'depends': ['sale_management', 'stock'],
'data': [
'security/ir.model.access.csv',
'wizard/wizard_product_kit_views.xml',
'views/product_template_views.xml',
'views/sale_order_views.xml',
'views/sale_portal_template.xml',
'views/report_invoice.xml',
]
}
3 changes: 3 additions & 0 deletions product_kit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import product_template
from . import sale_order_line
from . import sale_order
8 changes: 8 additions & 0 deletions product_kit/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from odoo import fields, models


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

kit = fields.Boolean(string="has kit ?", default=False, help="To enable new product type")
subproduct = fields.Many2many(comodel_name="product.product", string="Sub Product", help="Select subproduct if kit is enabled")
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 fields, models


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

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


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

has_kit = fields.Boolean(related="product_template_id.kit", store=True, help="Check product has kit enable or not")
is_kit = fields.Boolean(string="Is kit", default=False, help="Distinguish main product and subproduct. If true it is sub product")

def open_kit_wizard(self):
for record in self:
sale_order_line_id = record.id
sale_order_id = record.order_id.id

existing_lines = []

# Fetching existing order lines from sale order
existing_lines = self.env['sale.order.line'].search([
('linked_line_id', '=', sale_order_line_id),
('order_id', '=', sale_order_id)
])

# Creating dictionary with product id as key and quantity as value from existing order line
existing_dict = {
line.product_id.id: line.product_uom_qty for line in existing_lines
}
product_commands = []

# Looping through all the subproduct of kit enabled product
for product in record.product_template_id.subproduct:
qty = existing_dict.get(product.id, 1) # Fetching quantity of product if not found return 1
# Creating command to create new linked record
product_commands.append(
Command.create({
"product_id": product.id,
"quantity": qty
})
)

# Populating wizard models
wizard = self.env['wizard.product.kit'].create({
"product_ids": product_commands
})

return {
'type': 'ir.actions.act_window',
'name': 'Product Kit',
'res_model': 'wizard.product.kit',
'view_mode': 'form',
'target': 'new',
"res_id": wizard.id,
"context": {
"default_sale_order_id": record.order_id.id,
}
}
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
access_wizard_product_kit,access_wizard_product_kit,model_wizard_product_kit,base.group_user,1,1,1,0
access_wizard_product_kit_add,access_wizard_product_kit_add,model_wizard_product_kit_add,base.group_user,1,1,1,0
16 changes: 16 additions & 0 deletions product_kit/views/product_template_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<odoo>

<record id="product_template_form_view" model="ir.ui.view">
<field name="name">product.template.form.inherit.product.kit</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view" />
<field name="arch" type="xml">
<xpath expr="//group[@name='group_general']" position="inside">
<field name="kit" />
<field name="subproduct" widget="many2many_tags" invisible="not kit" />
</xpath>
</field>
</record>

</odoo>
13 changes: 13 additions & 0 deletions product_kit/views/report_invoice.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?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.print_in_report) or
(not line.sale_line_ids.filtered('is_kit'))
</attribute>
</xpath>
</template>

</odoo>
41 changes: 41 additions & 0 deletions product_kit/views/sale_order_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_order_form" model="ir.ui.view">
<field name="name">view.sale.form.order.line.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="print_in_report" />
</xpath>

<xpath expr="//field[@name='order_line']/list//field[@name='product_template_id']" position="after">
<button type="object" name="open_kit_wizard" class="btn btn-success" invisible="not has_kit or state in('sale')" string="+" />
</xpath>

<xpath expr="//field[@name='order_line']/list" position="attributes">
<attribute name="decoration-danger">is_kit</attribute>
</xpath>

<xpath expr="//field[@name='order_line']/list//field[@name='product_id']" position="attributes">
<attribute name="readonly">is_kit</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_template_id']" position="attributes">
<attribute name="readonly">is_kit</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_uom_qty']" position="attributes">
<attribute name="readonly">is_kit</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='customer_lead']" position="attributes">
<attribute name="readonly">is_kit</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='price_unit']" position="attributes">
<attribute name="readonly">is_kit</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='tax_id']" position="attributes">
<attribute name="readonly">is_kit</attribute>
</xpath>

</field>
</record>
</odoo>
10 changes: 10 additions & 0 deletions product_kit/views/sale_portal_template.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<odoo>

<template id="sale_preview_subproduct" inherit_id="sale.sale_order_portal_content">
<xpath expr="//tbody[hasclass('sale_tbody')]//tr//t" position="attributes">
<attribute name="t-if">(sale_order.print_in_report and line.is_kit) or (not line.is_kit)</attribute>
</xpath>
</template>

</odoo>
1 change: 1 addition & 0 deletions product_kit/wizard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import wizard_product_kit
78 changes: 78 additions & 0 deletions product_kit/wizard/wizard_product_kit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from odoo import api, fields, models
from odoo.exceptions import UserError


class WizardProductKit(models.TransientModel):
_name = 'wizard.product.kit'
_description = "Wizard to add product kit"

# sale_order_id = fields.Many2one(comodel_name="sale.order")
product_ids = fields.One2many(
comodel_name="wizard.product.kit.add",
inverse_name="kit_id",
string="Product"
)

def add_product_kits(self):
sale_order_id = self.env.context.get("default_sale_order_id")
main_order_line_id = self.env.context.get("active_id")

existing_line = self.env['sale.order.line'].search([
('linked_line_id', '=', main_order_line_id),
('order_id', '=', sale_order_id)
])
existing_product_ids = existing_line.mapped('product_id.id')

kits_price = 0
for product in self.product_ids:
# if product already in sale order line only update quantity and price
if product.product_id.id in existing_product_ids:
for line in existing_line:
if line.product_id.id == product.product_id.id:
line.write({
"product_uom_qty": product.quantity,
"price_unit": 0
})
# If not found create new line
else:
new_sale_order_line = self.env['sale.order.line'].create({
"product_id": product.product_id.id,
"order_id": sale_order_id,
"product_uom_qty": product.quantity,
"linked_line_id": main_order_line_id,
"price_unit": 0,
"is_kit": True,
})
if not new_sale_order_line:
raise UserError("something went wrong!!!")

kits_price += product.price

# Updating main order line price
order_line = self.env['sale.order.line'].browse(main_order_line_id)
order_line.write({
"price_subtotal": (order_line.product_uom_qty * order_line.product_id.list_price) + kits_price
})

return {"type": "ir.actions.act_window_close"}


class WizardProductKitAdd(models.TransientModel):
_name = 'wizard.product.kit.add'
_description = 'Wizard to add product kit list'

product_id = fields.Many2one(
comodel_name="product.product",
string="Name",
)
quantity = fields.Float(string='Quantity', default=1.0)
price = fields.Float(string='Price', compute="_compute_price")
kit_id = fields.Many2one(
comodel_name="wizard.product.kit",
string="Kit Name"
)

@api.depends("quantity")
def _compute_price(self):
for record in self:
record.price = record.quantity * record.product_id.list_price
26 changes: 26 additions & 0 deletions product_kit/wizard/wizard_product_kit_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<odoo>

<record id="wizard_product_kit_view_form" model="ir.ui.view">
<field name="name">Product Kit Wizard</field>
<field name="model">wizard.product.kit</field>
<field name="arch" type="xml">
<form string="Add Kit">
<sheet>
<field name="product_ids">
<list create="False" editable="bottom" delete="False" open_form_view="False">
<field name="product_id" readonly="True" />
<field name="quantity" />
<field name="price" />
</list>
</field>
</sheet>
<footer>
<button string="Confirm" type="object" name="add_product_kits" class="btn-primary" />
<button string="Cancel" special="cancel" />
</footer>
</form>
</field>
</record>

</odoo>