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 product
from . import project
from . import sale_order

View File

@@ -0,0 +1,14 @@
# Copyright 2017 Tecnativa - Sergio Teruel
# Copyright 2017 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ProductTemplate(models.Model):
_inherit = "product.template"
invoicing_finished_task = fields.Boolean(
string="Invoicing control by task",
help="Invoice the order lines only when the task is set to invoiceable",
)

View File

@@ -0,0 +1,67 @@
# Copyright 2017 Camptocamp SA
# Copyright 2017 Tecnativa - Sergio Teruel
# Copyright 2017 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.exceptions import ValidationError
class ProjectTaskType(models.Model):
_inherit = "project.task.type"
invoiceable = fields.Boolean()
class ProjectTask(models.Model):
_inherit = "project.task"
invoiceable = fields.Boolean()
invoicing_finished_task = fields.Boolean(
related="sale_line_id.product_id.invoicing_finished_task",
)
@api.onchange("stage_id")
def _onchange_stage_id(self):
tasks = self.filtered(
lambda t: (
t.invoicing_finished_task
and t.stage_id.invoiceable
and not t.invoiceable
)
)
tasks.toggle_invoiceable()
def toggle_invoiceable(self):
self._check_sale_line_state()
for task in self:
task.invoiceable = not task.invoiceable
def write(self, vals):
if "sale_line_id" in vals:
self._check_sale_line_state(vals["sale_line_id"])
return super().write(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get("sale_line_id"):
self._check_sale_line_state(vals["sale_line_id"])
return super().create(vals_list)
def _check_sale_line_state(self, sale_line_id=False):
sale_lines = self.mapped("sale_line_id")
if sale_line_id:
sale_lines |= self.env["sale.order.line"].browse(sale_line_id)
for sale_line in sale_lines:
if (
sale_line.state == "cancel"
or sale_line.invoice_status == "invoiced"
or sale_line.order_id.locked
):
raise ValidationError(
self.env._(
"You cannot create/modify a task related with a "
"invoiced, locked or cancel sale order line "
)
)

View File

@@ -0,0 +1,67 @@
# Copyright 2017 Tecnativa - Sergio Teruel
# Copyright 2017 Tecnativa - Carlos Dauden
# Copyright 2025 Tecnativa - Víctor Martínez
# 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"
task_ids = fields.One2many(
comodel_name="project.task",
inverse_name="sale_line_id",
string="Tasks",
)
@api.depends("task_ids.invoiceable")
def _compute_invoice_status(self):
res = super()._compute_invoice_status()
for item in self.filtered(lambda x: x.task_ids and x.invoice_status != "no"):
if not all(
t.invoiceable for t in item.task_ids if t.invoicing_finished_task
):
item.invoice_status = "no"
return res
@api.depends("task_ids.invoiceable")
def _compute_qty_to_invoice(self):
lines = self.filtered(
lambda x: (
x.product_id.type == "service"
and x.product_id.invoicing_finished_task
and x.product_id.service_tracking
in ["task_global_project", "task_in_project"]
and not all(x.task_ids.mapped("invoiceable"))
)
)
if lines:
lines.update({"qty_to_invoice": 0.0})
return super(SaleOrderLine, self - lines)._compute_qty_to_invoice()
def _timesheet_compute_delivered_quantity_domain(self):
vals = super()._timesheet_compute_delivered_quantity_domain()
vals = (
["|", ("amount", "<=", 0.0)]
+ vals
+ [
# don't update the qty on sale order lines which are not
# with a product invoiced on ordered qty +
# invoice_finished task = True
"|",
("so_line.product_id.invoice_policy", "=", "delivery"),
("so_line.product_id.invoicing_finished_task", "=", False),
]
)
return vals
@api.depends(
"qty_delivered_method",
"analytic_line_ids.so_line",
"analytic_line_ids.unit_amount",
"analytic_line_ids.product_uom_id",
"task_ids.invoiceable",
)
def _compute_qty_delivered(self):
return super()._compute_qty_delivered()