Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import sale_order_rma_wizard
from . import stock_picking_return

View file

@ -0,0 +1,270 @@
# Copyright 2020 Tecnativa - Ernesto Tejeda
# Copyright 2022 Tecnativa - Víctor Martínez
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import SUPERUSER_ID, _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare
class SaleOrderRmaWizard(models.TransientModel):
_name = "sale.order.rma.wizard"
_description = "Sale Order Rma Wizard"
def _domain_location_id(self):
sale = self.env["sale.order"].browse(self.env.context.get("active_id"))
rma_loc = (
self.env["stock.warehouse"]
.search([("company_id", "=", sale.company_id.id)])
.mapped("rma_loc_id")
)
return [("id", "child_of", rma_loc.ids)]
operation_id = fields.Many2one(
comodel_name="rma.operation",
string="Requested operation",
)
order_id = fields.Many2one(
comodel_name="sale.order",
default=lambda self: self.env.context.get("active_id", False),
)
line_ids = fields.One2many(
comodel_name="sale.order.line.rma.wizard",
inverse_name="wizard_id",
string="Lines",
)
location_id = fields.Many2one(
comodel_name="stock.location",
string="RMA location",
domain=_domain_location_id,
default=lambda r: r.order_id.warehouse_id.rma_loc_id.id,
)
commercial_partner_id = fields.Many2one(
comodel_name="res.partner",
related="order_id.partner_id.commercial_partner_id",
string="Commercial entity",
)
partner_shipping_id = fields.Many2one(
comodel_name="res.partner",
string="Shipping Address",
help="Will be used to return the goods when the RMA is completed",
)
custom_description = fields.Text(
help="Values coming from portal RMA request form custom fields",
)
is_return_all = fields.Boolean(string="Return All?", default=True)
def create_rma(self, from_portal=False):
self.ensure_one()
user_has_group_portal = self.env.user.has_group(
"base.group_portal"
) or self.env.user.has_group("base.group_public")
lines = self.line_ids.filtered(lambda r: r.quantity > 0.0)
val_list = [line._prepare_rma_values() for line in lines]
rma_model = (
self.env["rma"].with_user(SUPERUSER_ID)
if user_has_group_portal
else self.env["rma"]
)
rma = rma_model.create(val_list)
if from_portal:
rma._add_message_subscribe_partner()
# post messages
msg_list = [
'<a href="#" data-oe-model="rma" data-oe-id="%d">%s</a>' % (r.id, r.name)
for r in rma
]
msg = ", ".join(msg_list)
if len(msg_list) == 1:
self.order_id.message_post(body=_(msg + " has been created."))
elif len(msg_list) > 1:
self.order_id.message_post(body=_(msg + " have been created."))
rma.message_post_with_view(
"mail.message_origin_link",
values={"self": rma, "origin": self.order_id},
subtype_id=self.env.ref("mail.mt_note").id,
)
return rma
def create_and_open_rma(self):
self.ensure_one()
rma = self.create_rma()
if not rma:
return
rma.action_confirm()
action = self.sudo().env.ref("rma.rma_action").read()[0]
if len(rma) > 1:
action["domain"] = [("id", "in", rma.ids)]
elif rma:
action.update(
res_id=rma.id,
view_mode="form",
view_id=False,
views=False,
)
return action
class SaleOrderLineRmaWizard(models.TransientModel):
_name = "sale.order.line.rma.wizard"
_description = "Sale Order Line Rma Wizard"
wizard_id = fields.Many2one(comodel_name="sale.order.rma.wizard", string="Wizard")
order_id = fields.Many2one(
comodel_name="sale.order",
default=lambda self: self.env["sale.order"].browse(
self.env.context.get("active_id", False)
),
)
allowed_product_ids = fields.Many2many(
comodel_name="product.product", compute="_compute_allowed_product_ids"
)
product_id = fields.Many2one(
comodel_name="product.product",
string="Product",
required=True,
domain="[('id', 'in', allowed_product_ids)]",
)
uom_category_id = fields.Many2one(
comodel_name="uom.category",
related="product_id.uom_id.category_id",
)
quantity = fields.Float(
digits="Product Unit of Measure",
required=True,
compute="_compute_quantity",
store=True,
readonly=False,
)
allowed_quantity = fields.Float(digits="Product Unit of Measure", readonly=True)
uom_id = fields.Many2one(
comodel_name="uom.uom",
string="Unit of Measure",
domain="[('category_id', '=', uom_category_id)]",
required=True,
)
allowed_picking_ids = fields.Many2many(
comodel_name="stock.picking", compute="_compute_allowed_picking_ids"
)
picking_id = fields.Many2one(
comodel_name="stock.picking",
string="Delivery order",
domain="[('id', 'in', allowed_picking_ids)]",
)
move_id = fields.Many2one(comodel_name="stock.move", compute="_compute_move_id")
operation_id = fields.Many2one(
comodel_name="rma.operation",
string="Requested operation",
compute="_compute_operation_id",
store=True,
readonly=False,
)
sale_line_id = fields.Many2one(
comodel_name="sale.order.line",
)
description = fields.Text()
return_product_id = fields.Many2one(
"product.product",
help="Product to be returned if it's different from the originally delivered "
"item.",
)
different_return_product = fields.Boolean(
related="operation_id.different_return_product"
)
@api.depends("wizard_id.is_return_all", "allowed_quantity")
def _compute_quantity(self):
for rec in self:
if not rec.wizard_id.is_return_all:
rec.quantity = 0
else:
rec.quantity = rec.allowed_quantity
@api.depends("wizard_id.operation_id")
def _compute_operation_id(self):
for rec in self:
if rec.wizard_id.operation_id:
rec.operation_id = rec.wizard_id.operation_id
@api.onchange("product_id")
def onchange_product_id(self):
self.picking_id = False
self.uom_id = self.product_id.uom_id
@api.depends("picking_id")
def _compute_move_id(self):
for record in self:
move_id = False
if record.picking_id:
move_id = record.picking_id.move_ids.filtered(
lambda r: (
r.sale_line_id == record.sale_line_id
and r.sale_line_id.product_id == record.product_id
and r.sale_line_id.order_id == record.order_id
and r.state == "done"
)
)
record.move_id = move_id
@api.depends("order_id")
def _compute_allowed_product_ids(self):
for record in self:
product_ids = record.order_id.order_line.mapped("product_id.id")
record.allowed_product_ids = product_ids
@api.depends("product_id")
def _compute_allowed_picking_ids(self):
for record in self:
line = record.order_id.order_line.filtered(
lambda r: r.product_id == record.product_id
)
record.allowed_picking_ids = line.mapped("move_ids.picking_id").filtered(
lambda x: x.state == "done"
)
@api.constrains("quantity", "allowed_quantity")
def _check_quantity(self):
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
for rec in self:
if (
float_compare(
rec.quantity, rec.allowed_quantity, precision_digits=precision
)
== 1
):
raise ValidationError(
_(
"You can't exceed the allowed quantity for returning product "
"%(product)s.",
product=rec.product_id.display_name,
)
)
def _prepare_rma_values(self):
self.ensure_one()
partner_shipping = (
self.wizard_id.partner_shipping_id or self.order_id.partner_shipping_id
)
description = (self.description or "") + (
self.wizard_id.custom_description or ""
)
return {
"partner_id": self.order_id.partner_id.id,
"partner_invoice_id": self.order_id.partner_invoice_id.id,
"partner_shipping_id": partner_shipping.id,
"origin": self.order_id.name,
"company_id": self.order_id.company_id.id,
"location_id": self.wizard_id.location_id.id,
"order_id": self.order_id.id,
"picking_id": self.picking_id.id,
"move_id": self.move_id.id,
"product_id": self.product_id.id,
"product_uom_qty": self.quantity,
"product_uom": self.uom_id.id,
"operation_id": self.operation_id.id,
"description": description,
"return_product_id": self.return_product_id.id,
}

View file

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="sale_order_create_rma_action" model="ir.actions.act_window">
<field name="name">Create RMAs</field>
<field name="res_model">sale.order.rma.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="sale_order_rma_wizard_form_view" model="ir.ui.view">
<field name="name">sale.order.rma.wizard.form</field>
<field name="model">sale.order.rma.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="is_return_all" widget="boolean_toggle" />
<field name="operation_id" />
<field name="line_ids" nolabel="1" colspan="2">
<tree editable="bottom">
<field name="order_id" invisible="1" />
<field name="allowed_product_ids" invisible="1" />
<field name="product_id" options="{'no_create': True}" />
<field name="quantity" />
<field name="allowed_quantity" />
<field name="uom_category_id" invisible="1" />
<field
name="uom_id"
groups="uom.group_uom"
options="{'no_create': True}"
/>
<field name="allowed_picking_ids" invisible="1" />
<field
name="picking_id"
options="{'no_create': True}"
required="1"
/>
<field
name="operation_id"
attrs="{'required': [('quantity', '>', 0)]}"
/>
<field
name="return_product_id"
attrs="{'invisible': [('different_return_product', '=', False)], 'required': [('different_return_product', '=', True), ('quantity', '>', 0)]}"
/>
<field name="different_return_product" invisible="1" />
</tree>
</field>
</group>
<group>
<field name="commercial_partner_id" invisible="1" />
<field
name="partner_shipping_id"
domain="[('id', 'child_of', commercial_partner_id)]"
/>
<field
name="location_id"
options="{'no_create': True, 'no_open': True}"
groups="stock.group_stock_multi_locations"
required="1"
/>
</group>
<footer>
<button
name="create_and_open_rma"
string="Accept"
type="object"
class="btn-primary"
/>
<button string="Cancel" class="btn-secondary" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>

View file

@ -0,0 +1,29 @@
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import models
class ReturnPicking(models.TransientModel):
_inherit = "stock.return.picking"
def _prepare_rma_partner_values(self):
sale_order = self.picking_id.sale_id
if not sale_order:
return super()._prepare_rma_partner_values()
return (
sale_order.partner_id,
sale_order.partner_invoice_id,
sale_order.partner_shipping_id,
)
def _prepare_rma_values(self):
vals = super()._prepare_rma_values()
sale_order = self.picking_id.sale_id
if sale_order:
vals.update(
{
"order_id": sale_order.id,
}
)
return vals