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,9 @@
# Copyright (C) 2019-Today: Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import stock_invoice_state_mixin
from . import account_move
from . import stock_move
from . import stock_picking
from . import stock_picking_type
from . import stock_rule

View File

@@ -0,0 +1,58 @@
# Copyright (C) 2019-Today: Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models
class AccountMove(models.Model):
_inherit = "account.move"
def button_cancel(self):
"""
Inherit to update related picking as '2binvoiced' when the invoice is
cancelled (only for invoices, not refunds)
:return: bool
"""
result = super().button_cancel()
pickings = self.filtered(
lambda i: i.picking_ids and i.move_type in ["out_invoice", "in_invoice"]
).mapped("picking_ids")
self.mapped("invoice_line_ids.move_line_ids")._set_as_2binvoiced()
pickings._set_as_2binvoiced()
return result
def button_draft(self):
result = super().button_draft()
pickings = self.filtered(
lambda i: i.picking_ids and i.move_type in ["out_invoice", "in_invoice"]
).mapped("picking_ids")
self.mapped("invoice_line_ids.move_line_ids")._set_as_invoiced()
pickings._set_as_invoiced()
return result
def unlink(self):
"""
Inherit the unlink to update related picking as "2binvoiced"
(only for invoices, not refunds)
:return:
"""
pickings = self.filtered(
lambda i: i.picking_ids and i.move_type in ["out_invoice", "in_invoice"]
).mapped("picking_ids")
self.mapped("invoice_line_ids.move_line_ids")._set_as_2binvoiced()
pickings._set_as_2binvoiced()
return super().unlink()
def _reverse_moves(self, default_values_list=None, cancel=False):
reverse_moves = super()._reverse_moves(
default_values_list=default_values_list, cancel=cancel
)
for move, reverse_move in zip(self, reverse_moves, strict=False):
for line in move.invoice_line_ids:
reverse_line = reverse_move.invoice_line_ids.filtered(
lambda invoice_line, line=line: invoice_line.product_id
== line.product_id
)
reverse_line.move_line_ids = line.move_line_ids.ids
return reverse_moves

View File

@@ -0,0 +1,59 @@
# Copyright (C) 2019-Today: Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class StockInvoiceStateMixin(models.AbstractModel):
"""
Abstract model used to define invoice state with selection choices
"""
_name = "stock.invoice.state.mixin"
_description = "Stock Invoice State Mixin"
invoice_state = fields.Selection(
selection=[
("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable"),
],
string="Invoice Status",
default="none",
help="Invoiced: an invoice already exists\n"
"To Be Invoiced: need to be invoiced\n"
"Not Applicable: no invoice to create",
copy=False,
)
def _set_as_invoiced(self):
"""
Update invoice_state on current recordset to 'invoiced'
:return: self recordset (where the updated has been executed)
"""
return self._update_invoice_state("invoiced")
def _set_as_2binvoiced(self):
"""
Update invoice_state on current recordset to '2binvoiced'
:return: self recordset (where the updated has been executed)
"""
return self._update_invoice_state("2binvoiced")
def _set_as_not_billable(self):
"""
Update invoice_state on current recordset to 'invoiced'
:return: self recordset (where the updated has been executed)
"""
return self._update_invoice_state("none")
def _update_invoice_state(self, invoice_state):
"""
Execute the write
:param invoice_state: str
:return: self recordset (where the updated has been executed)
"""
records = self.filtered(lambda r: r.invoice_state != invoice_state)
if records:
records.write({"invoice_state": invoice_state})
return records

View File

@@ -0,0 +1,143 @@
# Copyright (C) 2019-Today: Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
from odoo.tools.float_utils import float_round
class StockMove(models.Model):
_name = "stock.move"
_inherit = [
_name,
"stock.invoice.state.mixin",
]
def _get_price_unit_invoice(self, inv_type, partner, qty=1):
"""
Gets price unit for invoice
:param inv_type: str
:param partner: res.partner
:param qty: float
:return: float
"""
if inv_type in ("in_invoice", "in_refund"):
price_unit = min(self.mapped("price_unit"))
else:
price_unit = max(self.mapped("price_unit"))
if price_unit > 0.0:
# Value informed by user should has preferency
return price_unit
product = self.mapped("product_id")
product.ensure_one()
sum(self.mapped("product_uom_qty"))
product_uom = self.mapped("product_uom")
company = fields.first(self).picking_id.company_id
# Only in the cases the stock.move has linked to Sale or
# Purchase Order it's possible use different Currencys
# TODO: Should this module make possible by include field
# currency_id in Stock.picking?
currency = company.currency_id
pickings = self.mapped("picking_id")
date_done = min(pickings.mapped("date_done"))
if inv_type in ("in_invoice", "in_refund"):
seller = product._select_seller(
partner_id=partner, quantity=qty, date=date_done
)
if not seller:
po_line_uom = self.mapped("product_uom") or product.uom_po_id
price_unit = self.env["account.tax"]._fix_tax_included_price_company(
product.uom_id._compute_price(product.standard_price, po_line_uom),
product.supplier_taxes_id,
# TODO: Should inform taxes_ids in stock.move?
product.supplier_taxes_id,
fields.first(self).company_id,
)
price_unit = product.currency_id._convert(
price_unit, currency, company, date_done, False
)
result = float_round(
price_unit,
precision_digits=max(
currency.decimal_places,
self.env["decimal.precision"].precision_get("Product Price"),
),
)
else:
price_unit = self.env["account.tax"]._fix_tax_included_price_company(
seller.price,
product.supplier_taxes_id,
# TODO: Should inform taxes_ids in stock.move?
product.supplier_taxes_id,
fields.first(self).company_id,
)
price_unit = seller.currency_id._convert(
price_unit, currency, company, date_done, False
)
price_unit = float_round(
price_unit,
precision_digits=max(
currency.decimal_places,
self.env["decimal.precision"].precision_get("Product Price"),
),
)
result = seller.product_uom._compute_price(price_unit, product_uom)
else:
# If partner given, search price in its sale pricelist
fiscal_position = (
self.env["account.fiscal.position"]
.with_company(company)
._get_fiscal_position(partner)
)
if partner and partner.property_product_pricelist:
price_unit = None
pricelist_rule_id = (
partner.property_product_pricelist._get_product_rule(
product,
qty or 1.0,
uom=product_uom,
date=date_done,
)
)
pricelist_rule = self.env["product.pricelist.item"].browse(
pricelist_rule_id
)
price_unit = pricelist_rule._compute_price(
product,
qty,
product_uom,
date_done,
currency=currency,
)
else:
price_unit = product.lst_price
result = product._get_tax_included_unit_price(
company,
currency,
date_done,
"sale",
fiscal_position=fiscal_position,
product_price_unit=price_unit,
product_currency=currency,
)
return result
def _prepare_extra_move_vals(self, qty):
"""Copy invoice state for a new extra stock move"""
values = super()._prepare_extra_move_vals(qty)
values["invoice_state"] = self.invoice_state
return values
def _prepare_move_split_vals(self, uom_qty):
"""Copy invoice state for a new splitted stock move"""
values = super()._prepare_move_split_vals(uom_qty)
values["invoice_state"] = self.invoice_state
return values

View File

@@ -0,0 +1,50 @@
# Copyright (C) 2019-Today: Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, models
class StockPicking(models.Model):
_name = "stock.picking"
_inherit = [
_name,
"stock.invoice.state.mixin",
]
def set_to_be_invoiced(self):
"""
Button to set Invoice State to To Be Invoice.
"""
self._set_as_2binvoiced()
self.mapped("move_ids")._set_as_2binvoiced()
def set_as_invoiced(self):
"""
Button to set Invoice State to Invoiced.
"""
self._set_as_invoiced()
self.mapped("move_ids")._set_as_invoiced()
def set_as_not_billable(self):
"""
Button to set Invoice State to Not Billable.
"""
self._set_as_not_billable()
self.mapped("move_ids")._set_as_not_billable()
def _get_partner_to_invoice(self):
self.ensure_one()
partner = self.partner_id
return partner.address_get(["invoice"]).get("invoice")
def action_assign(self):
"""If any stock move is to be invoiced, picking status is updated"""
if any(m.invoice_state == "2binvoiced" for m in self.mapped("move_ids")):
self.write({"invoice_state": "2binvoiced"})
return super().action_assign()
@api.onchange("invoice_state")
def _onchange_invoice_state(self):
for record in self:
record._update_invoice_state(record.invoice_state)
record.mapped("move_ids")._update_invoice_state(record.invoice_state)

View File

@@ -0,0 +1,35 @@
# Copyright (C) 2019-Today: Odoo Community Association
# @ 2019-Today: Akretion - www.akretion.com.br -
# Magno Costa <magno.costa@akretion.com.br>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class PickingType(models.Model):
_inherit = "stock.picking.type"
count_picking_2binvoiced = fields.Integer(compute="_compute_picking_2binvoiced")
def _compute_picking_2binvoiced(self):
domains = {
"count_picking_2binvoiced": [("invoice_state", "=", "2binvoiced")],
}
for field in domains:
data = self.env["stock.picking"].read_group(
domains[field]
+ [
("state", "!=", "cancel"),
("invoice_state", "=", "2binvoiced"),
("picking_type_id", "in", self.ids),
],
["picking_type_id"],
["picking_type_id"],
)
count = {
x["picking_type_id"][0]: x["picking_type_id_count"]
for x in data
if x["picking_type_id"]
}
for record in self:
record[field] = count.get(record.id, 0)

View File

@@ -0,0 +1,14 @@
# Copyright (C) 2024-Today - Akretion (<http://www.akretion.com>).
# @author Magno Costa <magno.costa@akretion.com.br>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class StockRule(models.Model):
_inherit = "stock.rule"
def _get_custom_move_fields(self):
fields = super()._get_custom_move_fields()
fields += ["invoice_state"]
return fields