Skip to content
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 new_product_type/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import wizard
20 changes: 20 additions & 0 deletions new_product_type/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
'name': 'New Product Type',
'author': 'Aditi Pawar(adpaw)',
'license': 'LGPL-3',
'summary': 'Sell products as kits without Manufacturing or BoM',
'depends': [
"sale", "product", "account"
],
'data': [
'security/ir.model.access.csv',
'views/product_views.xml',
'views/sale_order_line_views.xml',
'views/sale_kit_wizard_views.xml',
'report/invoice_report.xml',
'report/sale_order_portal_report.xml',
'report/sale_order_report.xml'
],
'installable': True,
'auto_install': True
}
3 changes: 3 additions & 0 deletions new_product_type/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
15 changes: 15 additions & 0 deletions new_product_type/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from odoo import models, fields, api
from odoo.exceptions import ValidationError


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

is_kit = fields.Boolean(string='Is Kit', default=False)
sub_product_ids = fields.Many2many('product.product', 'product_template_kit_component_rel')

@api.constrains("sub_product_ids")
def _check_no_self_product_reference(self):
for record in self:
if record.product_variant_ids in record.sub_product_ids:
raise ValidationError("A product cannot be added as a sub-product in its own kit.")
20 changes: 20 additions & 0 deletions new_product_type/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from odoo import models, fields, api


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

has_kit_products = fields.Boolean(
compute='_compute_has_kit_products',
store=False
)

print_kit_in_report = fields.Boolean(
string="Print Kit Components in Report",
default=False
)

@api.depends('order_line.is_kit_line')
def _compute_has_kit_products(self):
for order in self:
order.has_kit_products = any(line.is_kit_line for line in order.order_line)
33 changes: 33 additions & 0 deletions new_product_type/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from odoo import models, fields, api
from odoo.exceptions import UserError


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

is_kit_line = fields.Boolean(related='product_id.product_tmpl_id.is_kit', store=True)
is_kit_sub_line = fields.Boolean(default=False)
kit_main_line_id = fields.Many2one('sale.order.line', string='Kit Main Line', ondelete='cascade')
kit_unit_price = fields.Float(default=0.0)

@api.ondelete(at_uninstall=False)
def _check_sub_kit_product(self):
for line in self:
if line.is_kit_sub_line:
raise UserError(
"You cannot delete a kit sub-product line directly. "
"Delete the main kit product line instead."
)

def action_open_kit_wizard(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Kit Sub Products',
'res_model': 'sale.kit.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_order_line_id': self.id,
},
}
15 changes: 15 additions & 0 deletions new_product_type/report/invoice_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template
id="report_invoice_document_inherit_print_option"
inherit_id="account.report_invoice_document">
<xpath expr="//t[@t-set='lines_to_report']" position="attributes">
<attribute name="t-value">
o._get_move_lines_to_report().filtered(
lambda l: not any(sl.is_kit_sub_line for sl in l.sale_line_ids)
or any(sl.order_id.print_kit_in_report for sl in l.sale_line_ids)
)
</attribute>
</xpath>
</template>
</odoo>
14 changes: 14 additions & 0 deletions new_product_type/report/sale_order_portal_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template
id="sale_order_portal_content_inherit_print_option"
inherit_id="sale.sale_order_portal_content">
<xpath expr="//t[@t-set='lines_to_report']" position="attributes">
<attribute name="t-value">
sale_order._get_order_lines_to_report().filtered(
lambda l: not l.is_kit_sub_line or sale_order.print_kit_in_report
)
</attribute>
</xpath>
</template>
</odoo>
14 changes: 14 additions & 0 deletions new_product_type/report/sale_order_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template
id="report_saleorder_document_inherit_print_option"
inherit_id="sale.report_saleorder_document">
<xpath expr="//t[@t-set='lines_to_report']" position="attributes">
<attribute name="t-value">
doc._get_order_lines_to_report().filtered(
lambda l: not l.is_kit_sub_line or doc.print_kit_in_report
)
</attribute>
</xpath>
</template>
</odoo>
3 changes: 3 additions & 0 deletions new_product_type/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_sale_kit_wizard,sale.kit.wizard,model_sale_kit_wizard,base.group_user,1,1,1,1
access_sale_kit_wizard_line,sale.kit.wizard.line,model_sale_kit_wizard_line,base.group_user,1,1,1,1
17 changes: 17 additions & 0 deletions new_product_type/views/product_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="product_template_form_view_kit_inherit" model="ir.ui.view">
<field name="name">product.template.form.kit.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="//field[@name='invoice_policy']" position="after">
<field name="is_kit"/>
</xpath>
<xpath expr="//field[@name='is_kit']" position="after">
<field name="sub_product_ids" widget="many2many_tags"
options="{'no_create': True}" invisible="not is_kit"/>
</xpath>
</field>
</record>
</odoo>
34 changes: 34 additions & 0 deletions new_product_type/views/sale_kit_wizard_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale_kit_wizard_form_view" model="ir.ui.view">
<field name="name">sale.kit.wizard.form</field>
<field name="model">sale.kit.wizard</field>
<field name="arch" type="xml">
<form string="Kit Sub Products">
<sheet>
<group>
<field name="product_id" string="Product" readonly="1"/>
<field name="order_line_id" invisible="1"/>
</group>
<separator string="SUB PRODUCTS"/>
<field name="wizard_line_ids" nolabel="1">
<list editable="bottom" create="0">
<field name="product_id" string="Product" readonly="1" force_save="1"/>
<field name="quantity"/>
<field name="price"/>
</list>
</field>
</sheet>
<footer>
<button name="action_confirm_kit"
type="object"
string="Confirm"
class="btn-primary"/>
<button string="Cancel"
class="btn-secondary"
special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
36 changes: 36 additions & 0 deletions new_product_type/views/sale_order_line_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<odoo>
<record id="sale_order_line_kit_button_inherit" model="ir.ui.view">
<field name="name">sale.order.line.kit.button.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='product_template_id']" position="after">
<button
name="action_open_kit_wizard"
type="object"
icon="fa-cubes"
title="Configure Kit Sub Products"
invisible="not is_kit_line or is_kit_sub_line or state == 'sale'"
class="btn-sm"/>
</xpath>
<xpath expr="//field[@name='payment_term_id']" position="after">
<field name="print_kit_in_report" invisible="not has_kit_products"/>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_id']" position="attributes">
<attribute name="readonly">is_kit_sub_line</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list/field[@name='product_template_id']" position="attributes">
<attribute name="readonly">is_kit_sub_line</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='product_uom_qty']" position="attributes">
<attribute name="readonly">is_kit_sub_line</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list/field[@name='tax_ids']" position="attributes">
<attribute name="readonly">is_kit_sub_line</attribute>
</xpath>
<xpath expr="//field[@name='order_line']/list//field[@name='price_unit']" position="attributes">
<attribute name="readonly">is_kit_sub_line</attribute>
</xpath>
</field>
</record>
</odoo>
2 changes: 2 additions & 0 deletions new_product_type/wizard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import sale_kit_wizard
from . import sale_kit_wizard_line
89 changes: 89 additions & 0 deletions new_product_type/wizard/sale_kit_wizard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from odoo import models, fields, api
from odoo.fields import Command


class SaleKitWizard(models.TransientModel):
_name = 'sale.kit.wizard'
_description = 'Sale Kit Sub Products Wizard'

order_line_id = fields.Many2one('sale.order.line', string='Order Line', required=True)
product_id = fields.Many2one('product.template', string='Product')
wizard_line_ids = fields.One2many(
'sale.kit.wizard.line',
inverse_name='wizard_id',
string='Sub Products',
)

@api.model
def default_get(self, fields_list):
res = super().default_get(fields_list)

active_model = self.env.context.get('active_model')
active_id = self.env.context.get('active_id')

if active_model != 'sale.order.line' or not active_id:
return res

sale_line = self.env['sale.order.line'].browse(active_id)
if not sale_line.product_id:
return res

product = sale_line.product_id
kit_sub_product = []

for sub in product.product_tmpl_id.sub_product_ids:
existing_line = sale_line.order_id.order_line.filtered(
lambda line: line.product_id == sub
and line.kit_main_line_id == sale_line
)
kit_sub_product.append(
Command.create({
'product_id': sub.id,
'quantity': existing_line.product_uom_qty
if existing_line else 1.0,
'price': existing_line.kit_unit_price
if existing_line else sub.lst_price,
})
)

res.update({
'product_id': product.product_tmpl_id.id,
'order_line_id': sale_line.id,
'wizard_line_ids': kit_sub_product,
})
return res

def action_confirm_kit(self):
self.ensure_one()

parent_line = self.order_line_id
order = parent_line.order_id
total_price = parent_line.product_id.lst_price

for wiz_line in self.wizard_line_ids:
existing_line = order.order_line.filtered(
lambda line: line.product_id == wiz_line.product_id
and line.kit_main_line_id == parent_line
)

values = {
'product_uom_qty': wiz_line.quantity,
'price_unit': 0.0,
'kit_unit_price': wiz_line.price,
'sequence': parent_line.sequence,
}

if existing_line:
existing_line.write(values)
else:
self.env['sale.order.line'].create({
**values,
'name': wiz_line.product_id.name,
'order_id': order.id,
'product_id': wiz_line.product_id.id,
'is_kit_sub_line': True,
'kit_main_line_id': parent_line.id,
})
total_price += wiz_line.price * wiz_line.quantity
parent_line.write({'price_unit': total_price})
return {'type': 'ir.actions.act_window_close'}
11 changes: 11 additions & 0 deletions new_product_type/wizard/sale_kit_wizard_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from odoo import models, fields


class SaleKitWizardLine(models.TransientModel):
_name = 'sale.kit.wizard.line'
_description = 'Sale Kit Wizard Line'

wizard_id = fields.Many2one('sale.kit.wizard', required=True, ondelete='cascade')
product_id = fields.Many2one('product.product', string='Product')
quantity = fields.Float(default=1.0, digits=(16, 2))
price = fields.Float(digits=(16, 2))