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,3 @@
from . import res_partner
from . import stock_picking
from . import sale_order

View File

@@ -0,0 +1,51 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo import api, fields, models
from odoo.exceptions import ValidationError
class ResPartner(models.Model):
_inherit = "res.partner"
invoicing_mode = fields.Selection(
selection_add=[("at_shipping", "At Shipping")],
ondelete={"at_shipping": "set default"},
)
one_invoice_per_shipping = fields.Boolean(
index=True,
help="Check this if you want to create one invoice per shipping using the"
" partner invoicing mode that should be different than 'At Shipping'.",
)
@api.model
def _commercial_fields(self):
return super()._commercial_fields() + [
"one_invoice_per_shipping",
]
@api.constrains(
"invoicing_mode", "one_invoice_per_shipping", "one_invoice_per_order"
)
def _check_invoicing_mode_one_invoice_per_shipping(self):
for partner in self:
if (
partner.invoicing_mode == "at_shipping"
and partner.one_invoice_per_shipping
):
raise ValidationError(
self.env._(
"You cannot configure the partner %(partner)s with "
"Invoicing Mode 'At Shipping' and 'One Invoice Per Shipping'!",
partner=partner.name,
),
)
if partner.one_invoice_per_shipping and partner.one_invoice_per_order:
raise ValidationError(
self.env._(
"You cannot configure the partner %(partner)s with "
"'One Invoice Per Order' and 'One Invoice Per Shipping'!",
partner=partner.name,
),
)

View File

@@ -0,0 +1,92 @@
# Copyright 2023 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class SaleOrder(models.Model):
_inherit = "sale.order"
one_invoice_per_shipping = fields.Boolean(
compute="_compute_one_invoice_per_shipping",
store=True,
index=True,
)
@api.depends("partner_invoice_id")
def _compute_one_invoice_per_shipping(self):
"""
Compute this field (instead a related) to avoid computing all
related sale orders if option changed on partner level.
"""
for order in self:
order.one_invoice_per_shipping = (
order.partner_invoice_id.one_invoice_per_shipping
)
def generate_invoices(
self,
companies=None,
invoicing_mode="standard",
last_execution_field="invoicing_mode_standard_last_execution",
):
saleorders = super().generate_invoices(
companies=companies,
invoicing_mode=invoicing_mode,
last_execution_field=last_execution_field,
)
# Validate the preceding generated invoices in draft mode.
description = self.env._(
"Validate the invoices generated by shipping for the "
"invoicing mode %(invoicing_mode_name)s"
)
self.with_delay(
description=description
)._validate_per_shipping_generated_invoices(
companies=companies, invoicing_mode=invoicing_mode
)
return saleorders
@api.model
def _validate_per_shipping_generated_invoices(
self, companies=None, invoicing_mode="standard"
) -> str:
"""
This will validate all draft invoices that have been generated.
:param companies: _description_, defaults to None
:type companies: _type_, optional
:param invoicing_mode: _description_, defaults to "standard"
:type invoicing_mode: str, optional
:return: String result for queue job
:rtype: AccountMove
"""
if companies is None:
companies = self.env.company
invoices = self.env["account.move"].search(
self._get_per_shipping_to_validate_invoices_domain(
companies=companies, invoicing_mode=invoicing_mode
)
)
for invoice in invoices:
invoice.with_delay()._validate_invoice()
for partner, __invoices in invoices.partition("partner_id").items():
partner._update_next_invoice_date()
return ",".join(invoices.mapped("display_name"))
def _get_per_shipping_to_validate_invoices_domain(
self, companies, invoicing_mode="standard"
) -> list:
"""
This will return the domain for invoices that should be posted.
:return: Domain
:rtype: list
"""
return [
("company_id", "in", companies.ids),
("move_type", "in", ("out_invoice", "out_refund")),
("state", "=", "draft"),
("partner_id.one_invoice_per_shipping", "=", True),
("partner_id.invoicing_mode", "=", invoicing_mode),
]

View File

@@ -0,0 +1,56 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo import api, models
class StockPicking(models.Model):
_inherit = "stock.picking"
def _action_done(self):
res = super()._action_done()
for picking in self:
if picking._invoice_at_shipping():
picking.with_delay()._invoicing_at_shipping()
return res
def _invoice_at_shipping(self):
"""Check if picking must be invoiced at shipping."""
self.ensure_one()
return self.picking_type_code == "outgoing" and (
self.sale_id.partner_invoice_id.invoicing_mode == "at_shipping"
or self.sale_id.partner_invoice_id.one_invoice_per_shipping
)
def _invoicing_at_shipping_validation(self, invoices):
return invoices.filtered(
lambda invoice: invoice.partner_id.invoicing_mode == "at_shipping"
)
@api.model
def _invoicing_at_shipping(self):
self.ensure_one()
sales = self._get_sales_order_to_invoice()
# Split invoice creation on partner sales grouping on invoice settings
sales_one_invoice_per_order = sales.filtered(
"partner_invoice_id.one_invoice_per_order"
)
invoices = self.env["account.move"]
if sales_one_invoice_per_order:
invoices |= sales_one_invoice_per_order.sudo()._create_invoices(
grouped=True
)
sales_many_invoice_per_order = sales - sales_one_invoice_per_order
if sales_many_invoice_per_order:
invoices |= sales_many_invoice_per_order.sudo()._create_invoices(
grouped=False
)
# The invoices per picking will use the invoicing_mode
for invoice in self._invoicing_at_shipping_validation(invoices):
invoice.with_delay()._validate_invoice()
return invoices or self.env._("Nothing to invoice.")
def _get_sales_order_to_invoice(self):
return self.move_ids.sale_line_id.order_id.filtered(
lambda r: r._get_invoiceable_lines()
)