Initial commit: Odoo 18.0-20251222 extra-addons
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled

This commit is contained in:
tocmo0nlord
2026-03-13 20:43:25 +00:00
parent 36e847a7df
commit adbe430761
9472 changed files with 1265727 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import sale_product_set_wizard

View File

@@ -0,0 +1,115 @@
# Copyright 2015 Anybox S.A.S
# Copyright 2016-2020 Camptocamp SA
# @author Simone Orsi <simahawk@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, exceptions, fields, models
class SaleProductSetWizard(models.TransientModel):
_inherit = "product.set.wizard"
_name = "sale.product.set.wizard"
_description = "Wizard model to add product set into a quotation"
order_id = fields.Many2one(
"sale.order",
"Sale Order",
required=True,
default=lambda self: self.env.context.get("active_id")
if self.env.context.get("active_model") == "sale.order"
else None,
ondelete="cascade",
)
partner_id = fields.Many2one(related="order_id.partner_id", ondelete="cascade")
skip_existing_products = fields.Boolean(
default=False,
help="Enable this to not add new lines "
"for products already included in SO lines.",
)
@api.depends_context("product_set_add__set_line_ids")
def _compute_product_set_line_ids(self):
line_ids = self.env.context.get("product_set_add__set_line_ids", [])
lines_from_ctx = self.env["product.set.line"].browse(line_ids)
for rec in self:
lines = lines_from_ctx.filtered(
lambda x, rec=rec: x.product_set_id == rec.product_set_id
)
if lines:
# Use the ones from ctx but make sure they belong to the same set.
rec.product_set_line_ids = lines
else:
# Fallback to all lines from current set
return super()._compute_product_set_line_ids()
def _check_partner(self):
"""Validate order partner against product set's partner if any."""
if not self.product_set_id.partner_id or self.env.context.get(
"product_set_add_skip_validation"
):
return
allowed_partners = self._allowed_order_partners()
if self.order_id.partner_id not in allowed_partners:
raise exceptions.ValidationError(
self.env._(
"You can use a sale order assigned "
"only to following partner(s): {}"
).format(", ".join(allowed_partners.mapped("name")))
)
return super()._check_partner()
def _allowed_order_partners(self):
"""Product sets' partners allowed for current sale order."""
partner_ids = self.env.context.get("allowed_order_partner_ids")
if partner_ids:
return self.env["res.partner"].browse(partner_ids)
return self.product_set_id.partner_id
def add_set(self):
"""Add product set, multiplied by quantity in sale order line"""
res = super().add_set()
if not self.order_id:
return res
order_lines = self._prepare_order_lines()
if order_lines:
self.order_id.write({"order_line": order_lines})
return order_lines
def _prepare_order_lines(self):
max_sequence = self._get_max_sequence()
order_lines = []
for seq, set_line in enumerate(self._get_lines(), start=1):
values = self.prepare_sale_order_line_data(set_line)
# When we play with sequence widget on a set of product,
# it's possible to have a negative sequence.
# In this case, the line is not added at the correct place.
# So we have to force it with the order of the line.
values.update({"sequence": max_sequence + seq})
order_lines.append((0, 0, values))
return order_lines
def _get_max_sequence(self):
max_sequence = 0
if self.order_id.order_line:
max_sequence = max(line.sequence for line in self.order_id.order_line)
return max_sequence
def _get_lines(self):
if not self.order_id:
yield from super()._get_lines()
so_product_ids = self.order_id.order_line.mapped("product_id").ids
for set_line in self.product_set_line_ids:
if self.skip_existing_products and set_line.product_id.id in so_product_ids:
continue
yield set_line
def prepare_sale_order_line_data(self, set_line, max_sequence=0):
self.ensure_one()
line_values = set_line.prepare_sale_order_line_values(
self.order_id, self.quantity, max_sequence=max_sequence
)
if set_line.display_type:
line_values.update(
{"name": set_line.name, "display_type": set_line.display_type}
)
return line_values

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="product_set_add_form_view" model="ir.ui.view">
<field name="name">sale.product.set.wizard.form.view</field>
<field name="model">sale.product.set.wizard</field>
<field name="arch" type="xml">
<form string="Add set in sale order line">
<group name="main" colspan="4">
<field
name="order_id"
invisible="context.get('default_order_id')"
domain="[('state', 'in', ('draft','sent'))]"
/>
<field name="partner_id" invisible="1" />
<field
name="product_set_id"
domain="['|',('partner_id', '=', False),('partner_id', '=', partner_id)]"
/>
<field name="quantity" />
<field name="skip_existing_products" />
</group>
<group name="lines" colspan="4">
<field
name="product_set_line_ids"
nolabel="1"
colspan="4"
widget="section_and_note_one2many"
domain="[('product_set_id', '=', product_set_id)]"
>
<list>
<field
name="product_id"
options="{'no_open': True, 'no_create': True}"
required="not display_type"
/>
<field name="display_type" column_invisible="True" />
<field name="name" widget="section_and_note_text" />
<control>
<create name="add_line_control" string="Add a line" />
<create
name="add_section_control"
string="Add a section"
context="{'default_display_type': 'line_section'}"
/>
<create
name="add_note_control"
string="Add a note"
context="{'default_display_type': 'line_note'}"
/>
</control>
</list>
</field>
</group>
<footer>
<button
name="add_set"
string="Add set"
type="object"
class="oe_highlight"
/>
<button special="cancel" string="Cancel" class="oe_link" />
</footer>
</form>
</field>
</record>
<record
id="act_open_wizard_product_set_add_from_order"
model="ir.actions.act_window"
>
<field name="name">Add set in sale order</field>
<field name="res_model">sale.product.set.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="product_set_add_form_view" />
<field name="domain">[]</field>
<field name="context">{'default_order_id': order_id}</field>
<field name="target">new</field>
</record>
<record id="act_open_wizard_product_set_add_from_set" model="ir.actions.act_window">
<field name="name">Add set to sale order</field>
<field name="res_model">sale.product.set.wizard</field>
<field name="binding_model_id" ref="product_set.model_product_set" />
<field name="view_mode">form</field>
<field name="view_id" ref="product_set_add_form_view" />
<field name="domain">[]</field>
<field name="context">{'default_product_set_id': product_set_id}</field>
<field name="target">new</field>
</record>
</odoo>