Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
3
partner_invoicing_mode_at_shipping/models/__init__.py
Normal file
3
partner_invoicing_mode_at_shipping/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import res_partner
|
||||
from . import stock_picking
|
||||
from . import sale_order
|
||||
51
partner_invoicing_mode_at_shipping/models/res_partner.py
Normal file
51
partner_invoicing_mode_at_shipping/models/res_partner.py
Normal 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,
|
||||
),
|
||||
)
|
||||
92
partner_invoicing_mode_at_shipping/models/sale_order.py
Normal file
92
partner_invoicing_mode_at_shipping/models/sale_order.py
Normal 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),
|
||||
]
|
||||
56
partner_invoicing_mode_at_shipping/models/stock_picking.py
Normal file
56
partner_invoicing_mode_at_shipping/models/stock_picking.py
Normal 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()
|
||||
)
|
||||
Reference in New Issue
Block a user