Files
stock-rma/rma_account/models/account_move.py
2022-11-29 13:56:53 +01:00

275 lines
11 KiB
Python

# Copyright 2017-22 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
from odoo import api, fields, models
from odoo.tools.float_utils import float_compare
class AccountMove(models.Model):
_inherit = "account.move"
@api.depends("line_ids.rma_line_ids")
def _compute_used_in_rma_count(self):
for inv in self:
rmas = self.mapped("line_ids.rma_line_ids")
inv.used_in_rma_count = len(rmas)
@api.depends("line_ids.rma_line_id")
def _compute_rma_count(self):
for inv in self:
rmas = self.mapped("line_ids.rma_line_id")
inv.rma_count = len(rmas)
def _prepare_invoice_line_from_rma_line(self, rma_line):
sequence = max(self.line_ids.mapped("sequence")) + 1 if self.line_ids else 10
qty = rma_line.qty_to_refund
if float_compare(qty, 0.0, precision_rounding=rma_line.uom_id.rounding) <= 0:
qty = 0.0
data = {
"move_id": self.id,
"product_uom_id": rma_line.uom_id.id,
"product_id": rma_line.product_id.id,
"price_unit": rma_line.company_id.currency_id._convert(
rma_line._get_price_unit(),
self.currency_id,
self.company_id,
self.date,
round=False,
),
"quantity": qty,
"discount": 0.0,
"rma_line_id": rma_line.id,
"sequence": sequence + 1,
}
return data
def _post_process_invoice_line_from_rma_line(self, new_line, rma_line):
new_line.rma_line_id = rma_line
new_line.name = "%s: %s" % (
self.add_rma_line_id.name,
new_line._get_computed_name(),
)
new_line.account_id = new_line._get_computed_account()
new_line._onchange_price_subtotal()
new_line._onchange_mark_recompute_taxes()
return True
@api.onchange("add_rma_line_id")
def on_change_add_rma_line_id(self):
if not self.add_rma_line_id:
return {}
if not self.partner_id:
self.partner_id = self.add_rma_line_id.partner_id.id
new_line = self.env["account.move.line"]
if self.add_rma_line_id not in (self.line_ids.mapped("rma_line_id")):
data = self._prepare_invoice_line_from_rma_line(self.add_rma_line_id)
new_line = new_line.new(data)
self._post_process_invoice_line_from_rma_line(
new_line, self.add_rma_line_id
)
# Compute invoice_origin.
origins = set(self.line_ids.mapped("rma_line_id.name"))
self.invoice_origin = ",".join(list(origins))
self.add_rma_line_id = False
self._onchange_currency()
rma_count = fields.Integer(compute="_compute_rma_count", string="# of RMA")
used_in_rma_count = fields.Integer(
compute="_compute_used_in_rma_count", string="# of Used in RMA"
)
add_rma_line_id = fields.Many2one(
comodel_name="rma.order.line",
string="Add from RMA line",
ondelete="set null",
help="Create a refund in based on an existing rma_line",
)
def action_view_used_in_rma(self):
rmas = self.mapped("line_ids.rma_line_ids")
return self._prepare_action_view_rma(rmas)
def action_view_rma(self):
rmas = self.mapped("line_ids.rma_line_id")
return self._prepare_action_view_rma(rmas)
def _prepare_action_view_rma(self, rmas):
if self.move_type in ["in_invoice", "in_refund"]:
action = self.env.ref("rma.action_rma_supplier_lines")
form_view = self.env.ref("rma.view_rma_line_supplier_form", False)
else:
action = self.env.ref("rma.action_rma_customer_lines")
form_view = self.env.ref("rma.view_rma_line_form", False)
result = action.sudo().read()[0]
rma_ids = rmas.ids
# choose the view_mode accordingly
if not rma_ids:
result["domain"] = [("id", "in", [])]
elif len(rma_ids) > 1:
result["domain"] = [("id", "in", rma_ids)]
else:
res = form_view
result["views"] = [(res and res.id or False, "form")]
result["res_id"] = rma_ids and rma_ids[0] or False
return result
def _stock_account_prepare_anglo_saxon_out_lines_vals(self):
product_model = self.env["product.product"]
res = super()._stock_account_prepare_anglo_saxon_out_lines_vals()
for line in res:
if line.get("product_id", False):
product = product_model.browse(line.get("product_id", False))
if (
line.get("account_id")
!= product.categ_id.property_stock_valuation_account_id.id
):
current_move = self.browse(line.get("move_id", False))
current_rma = current_move.invoice_line_ids.filtered(
lambda x: x.rma_line_id and x.product_id.id == product.id
).mapped("rma_line_id")
if len(current_rma) == 1:
line.update({"rma_line_id": current_rma.id})
elif len(current_rma) > 1:
find_with_label_rma = current_rma.filtered(
lambda x: x.name == line.get("name")
)
if len(find_with_label_rma) == 1:
line.update({"rma_line_id": find_with_label_rma.id})
return res
def _stock_account_get_last_step_stock_moves(self):
rslt = super(AccountMove, self)._stock_account_get_last_step_stock_moves()
for invoice in self.filtered(lambda x: x.move_type == "out_invoice"):
rslt += invoice.mapped("line_ids.rma_line_id.move_ids").filtered(
lambda x: x.state == "done" and x.location_dest_id.usage == "customer"
)
for invoice in self.filtered(lambda x: x.move_type == "out_refund"):
# Add refunds generated from the RMA
rslt += invoice.mapped("line_ids.rma_line_id.move_ids").filtered(
lambda x: x.state == "done" and x.location_id.usage == "customer"
)
return rslt
class AccountMoveLine(models.Model):
_inherit = "account.move.line"
@api.model
def name_search(self, name, args=None, operator="ilike", limit=100):
"""Allows to search by Invoice number. This has to be done this way,
as Odoo adds extra args to name_search on _name_search method that
will make impossible to get the desired result."""
if not args:
args = []
lines = self.search([("move_id.name", operator, name)] + args, limit=limit)
res = lines.name_get()
if limit:
limit_rest = limit - len(lines)
else:
# limit can be 0 or None representing infinite
limit_rest = limit
if limit_rest or not limit:
args += [("id", "not in", lines.ids)]
res += super(AccountMoveLine, self).name_search(
name, args=args, operator=operator, limit=limit_rest
)
return res
def name_get(self):
res = []
if self.env.context.get("rma"):
for inv in self:
if inv.move_id.ref:
res.append(
(
inv.id,
"INV:%s | REF:%s | ORIG:%s | PART:%s | QTY:%s"
% (
inv.move_id.name or "",
inv.move_id.invoice_origin or "",
inv.move_id.ref or "",
inv.product_id.name,
inv.quantity,
),
)
)
elif inv.move_id.name:
res.append(
(
inv.id,
"INV:%s | ORIG:%s | PART:%s | QTY:%s"
% (
inv.move_id.name or "",
inv.move_id.invoice_origin or "",
inv.product_id.name,
inv.quantity,
),
)
)
else:
res.append(super(AccountMoveLine, inv).name_get()[0])
return res
else:
return super(AccountMoveLine, self).name_get()
def _compute_used_in_rma_count(self):
for invl in self:
rma_lines = invl.mapped("rma_line_ids")
invl.used_in_rma_line_count = len(rma_lines)
def _compute_rma_count(self):
for invl in self:
rma_lines = invl.mapped("rma_line_id")
invl.rma_line_count = len(rma_lines)
used_in_rma_line_count = fields.Integer(
compute="_compute_used_in_rma_line_count", string="# of RMA"
)
rma_line_count = fields.Integer(compute="_compute_rma_count", string="# of RMA")
rma_line_ids = fields.One2many(
comodel_name="rma.order.line",
inverse_name="account_move_line_id",
string="RMA",
readonly=True,
help="This will contain the RMA lines for the invoice line",
)
rma_line_id = fields.Many2one(
comodel_name="rma.order.line",
string="RMA line",
ondelete="set null",
help="This will contain the rma line that originated this line",
)
def _stock_account_get_anglo_saxon_price_unit(self):
self.ensure_one()
price_unit = super(
AccountMoveLine, self
)._stock_account_get_anglo_saxon_price_unit()
rma_line = self.rma_line_id or self.env["rma.order.line"]
if rma_line:
is_line_reversing = bool(self.move_id.reversed_entry_id)
qty_to_refund = self.product_uom_id._compute_quantity(
self.quantity, self.product_id.uom_id
)
posted_invoice_lines = rma_line.move_line_ids.filtered(
lambda l: l.move_id.move_type == "out_refund"
and l.move_id.state == "posted"
and bool(l.move_id.reversed_entry_id) == is_line_reversing
)
qty_refunded = sum(
x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id)
for x in posted_invoice_lines
)
product = self.product_id.with_company(self.company_id).with_context(
is_returned=is_line_reversing
)
average_price_unit = product._compute_average_price(
qty_refunded, qty_to_refund, rma_line._get_in_moves()
)
if average_price_unit:
price_unit = self.product_id.uom_id.with_company(
self.company_id
)._compute_price(average_price_unit, self.product_uom_id)
return price_unit