Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
4
sale_delivery_state/models/__init__.py
Executable file
4
sale_delivery_state/models/__init__.py
Executable file
@@ -0,0 +1,4 @@
|
||||
from . import sale_order
|
||||
from . import sale_order_line
|
||||
from . import res_company
|
||||
from . import res_config_settings
|
||||
12
sale_delivery_state/models/res_company.py
Executable file
12
sale_delivery_state/models/res_company.py
Executable file
@@ -0,0 +1,12 @@
|
||||
# Copyright 2023 Manuel Regidor <manuel.regidor@sygel.es>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
skip_service_sale_delivery_state = fields.Boolean(
|
||||
string="Skip Service products for Sale Delivery State"
|
||||
)
|
||||
14
sale_delivery_state/models/res_config_settings.py
Executable file
14
sale_delivery_state/models/res_config_settings.py
Executable file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2023 Manuel Regidor <manuel.regidor@sygel.es>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
skip_service_sale_delivery_state = fields.Boolean(
|
||||
string="Skip Service products for Sale Delivery State",
|
||||
related="company_id.skip_service_sale_delivery_state",
|
||||
readonly=False,
|
||||
)
|
||||
116
sale_delivery_state/models/sale_order.py
Executable file
116
sale_delivery_state/models/sale_order.py
Executable file
@@ -0,0 +1,116 @@
|
||||
# Copyright 2018 Akretion (http://www.akretion.com).
|
||||
# @author Pierrick BRUN <pierrick.brun@akretion.com>
|
||||
# Copyright 2018 Camptocamp
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
# Copyright 2023 Manuel Regidor <manuel.regidor@sygel.es>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = "sale.order"
|
||||
|
||||
delivery_status = fields.Selection(
|
||||
# Compute method have a different name then the field because
|
||||
# the method _compute_delivery_status already exist in odoo sale_stock
|
||||
compute="_compute_oca_delivery_status",
|
||||
store=True,
|
||||
# Respect the same order as in sale_stock
|
||||
# Including the 'started' state
|
||||
# that is not used here but we compute it
|
||||
# if pickings are available, to be compatible.
|
||||
selection=[
|
||||
("pending", "Not Delivered"),
|
||||
("started", "Started"),
|
||||
("partial", "Partially Delivered"),
|
||||
("full", "Fully Delivered"),
|
||||
],
|
||||
)
|
||||
|
||||
force_delivery_state = fields.Boolean(
|
||||
help=(
|
||||
"Allow to enforce done state of delivery, for instance if some"
|
||||
" quantities were cancelled"
|
||||
),
|
||||
)
|
||||
|
||||
def _all_qty_delivered(self):
|
||||
"""
|
||||
Returns True if all line have qty_delivered >= to ordered quantities
|
||||
|
||||
If `delivery` module is installed, ignores the lines with delivery costs
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
self.ensure_one()
|
||||
# Skip delivery costs lines
|
||||
sale_lines = self.order_line.filtered(
|
||||
lambda rec: not rec._is_delivery() and not rec.skip_sale_delivery_state
|
||||
)
|
||||
precision = self.env["decimal.precision"].precision_get(
|
||||
"Product Unit of Measure"
|
||||
)
|
||||
return all(
|
||||
float_compare(
|
||||
line.qty_delivered, line.product_uom_qty, precision_digits=precision
|
||||
)
|
||||
>= 0
|
||||
for line in sale_lines
|
||||
)
|
||||
|
||||
def _partially_delivered(self):
|
||||
"""
|
||||
Returns True if at least one line is delivered
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
self.ensure_one()
|
||||
# Skip delivery costs lines
|
||||
sale_lines = self.order_line.filtered(
|
||||
lambda rec: not rec._is_delivery() and not rec.skip_sale_delivery_state
|
||||
)
|
||||
precision = self.env["decimal.precision"].precision_get(
|
||||
"Product Unit of Measure"
|
||||
)
|
||||
return any(
|
||||
not float_is_zero(line.qty_delivered, precision_digits=precision)
|
||||
for line in sale_lines
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"order_line.qty_delivered",
|
||||
"order_line.skip_sale_delivery_state",
|
||||
"state",
|
||||
"force_delivery_state",
|
||||
)
|
||||
def _compute_oca_delivery_status(self):
|
||||
for order in self:
|
||||
if order.state in ("draft", "cancel"):
|
||||
order.delivery_status = None
|
||||
elif order.force_delivery_state or order._all_qty_delivered():
|
||||
order.delivery_status = "full"
|
||||
elif order._partially_delivered():
|
||||
order.delivery_status = "partial"
|
||||
elif order._is_delivery_status_started():
|
||||
order.delivery_status = "started"
|
||||
else:
|
||||
order.delivery_status = "pending"
|
||||
|
||||
def _is_delivery_status_started(self):
|
||||
# Loose dep on sale_stock. Feel free to customize this method
|
||||
# to add your own logic or to create sale_stock glue module.
|
||||
# NOTE: as the delivery_status is stored the update of a picking
|
||||
# won't have any effect here. Hence, if you really want to
|
||||
# fully support the started state, you should trigger the update
|
||||
# of the sale order when a picking is updated.
|
||||
# For now, we don't care that much as this state was not used before.
|
||||
has_pickings = "picking_ids" in self._fields
|
||||
return has_pickings and any(p.state == "done" for p in self.picking_ids)
|
||||
|
||||
def action_force_delivery_state(self):
|
||||
self.write({"force_delivery_state": True})
|
||||
|
||||
def action_unforce_delivery_state(self):
|
||||
self.write({"force_delivery_state": False})
|
||||
27
sale_delivery_state/models/sale_order_line.py
Executable file
27
sale_delivery_state/models/sale_order_line.py
Executable file
@@ -0,0 +1,27 @@
|
||||
# Copyright 2023 Manuel Regidor <manuel.regidor@sygel.es>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
skip_sale_delivery_state = fields.Boolean(
|
||||
string="Skip Delivery State",
|
||||
compute="_compute_skip_sale_delivery_state",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
@api.depends("company_id", "product_id")
|
||||
def _compute_skip_sale_delivery_state(self):
|
||||
for line in self:
|
||||
skip_sale_delivery_state = False
|
||||
if (
|
||||
line.product_id
|
||||
and line.product_id.type == "service"
|
||||
and line.company_id.skip_service_sale_delivery_state
|
||||
):
|
||||
skip_sale_delivery_state = True
|
||||
line.skip_sale_delivery_state = skip_sale_delivery_state
|
||||
Reference in New Issue
Block a user